From 5a43ccffcf72046a478eb0d8c1af92bfb253381a Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Thu, 11 Apr 2024 14:29:27 +0800 Subject: [PATCH 01/28] no message --- .../pages/homework_correction/job_home.dart | 146 ++++++++++++++++++ marking_app/lib/pages/mainPage.dart | 17 +- 2 files changed, 152 insertions(+), 11 deletions(-) create mode 100644 marking_app/lib/pages/homework_correction/job_home.dart diff --git a/marking_app/lib/pages/homework_correction/job_home.dart b/marking_app/lib/pages/homework_correction/job_home.dart new file mode 100644 index 0000000..3fcb9db --- /dev/null +++ b/marking_app/lib/pages/homework_correction/job_home.dart @@ -0,0 +1,146 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:marking_app/common/mixin/common.dart'; +import 'package:marking_app/common/model/marking/marking_list_params.dart'; +import 'package:marking_app/utils/index.dart'; +import 'package:marking_app/utils/my_text.dart'; + +import '../../utils/my_future_builder.dart'; + +class JobHome extends StatefulWidget { + const JobHome({super.key}); + + @override + State createState() => _JobHomeState(); +} + +class _JobHomeState extends State with CommonMixin, AutomaticKeepAliveClientMixin { + @override + bool get wantKeepAlive => true; + + late Future _future; + List entrances = [ + EntranceModel( + title: '作业批阅', + image: '', + navigationUrl: '', + ), + EntranceModel( + title: '学生历史作业', + image: '', + navigationUrl: '', + ), + EntranceModel( + title: '知识点掌握', + image: '', + navigationUrl: '', + ), + EntranceModel( + title: '答题轨迹', + image: '', + navigationUrl: '', + ), + EntranceModel( + title: '优先批阅设定', + image: '', + navigationUrl: '', + ), + EntranceModel( + title: '批阅设置', + image: '', + navigationUrl: '', + ), + ]; + + @override + void initState() { + _future = getData(); + super.initState(); + } + + Future getData() async { + var _client = await getClient(); + var _result = await _client.getJobsByPage(MarkingListParams( + isFinish: false, + page: 1, + limit: 1, + pageType: 0, + )); + if (_result == null) return 0; + return _result.data?.total ?? 0; + } + + @override + Widget build(BuildContext context) { + super.build(context); + + return AnnotatedRegion( + value: const SystemUiOverlayStyle( + systemNavigationBarColor: Color(0xFF000000), + systemNavigationBarDividerColor: null, + statusBarColor: Colors.white, + systemNavigationBarIconBrightness: Brightness.light, + statusBarIconBrightness: Brightness.dark, + statusBarBrightness: Brightness.light, + ), + child: Scaffold( + appBar: AppBar( + backgroundColor: Colors.white, + centerTitle: true, // 标题居中 + title: quickText('我的作业管理'), + systemOverlayStyle: SystemUiOverlayStyle.dark, + ), + backgroundColor: Color.fromRGBO(244, 244, 244, 1), + body: RefreshIndicator( + onRefresh: () async { + _future = getData(); + toUpState(setState, () {}, mounted); + }, + child: MyFutureBuilder.buildFutureBuilderOfSingleInstance(context, _future, (data) { + if (data == null) + return Center( + child: Container( + child: TextButton( + onPressed: () { + _future = getData(); + toUpState(setState, () {}, mounted); + }, + child: quickText('没有获取到数据,点击重试'), + ), + ), + ); + + return Container( + child: GridView( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + mainAxisSpacing: 10.r, + crossAxisSpacing: 10.r, + childAspectRatio: 556 / 112, + ), + children: entrances.map((e) { + return Container( + alignment: Alignment.center, + child: Row( + children: [ + quickText(e.title), + ], + ), + ); + }).toList(), + ), + ); + }), + ), + ), + ); + } +} + +class EntranceModel extends Object { + String title; + String image; + String navigationUrl; + EntranceModel({required this.title, required this.image, required this.navigationUrl}); +} diff --git a/marking_app/lib/pages/mainPage.dart b/marking_app/lib/pages/mainPage.dart index b211b96..acad5d6 100644 --- a/marking_app/lib/pages/mainPage.dart +++ b/marking_app/lib/pages/mainPage.dart @@ -16,11 +16,9 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:marking_app/common/mixin/common.dart'; import 'package:marking_app/common/model/common/base_structure_result.dart'; import 'package:marking_app/common/model/user/user_info.dart'; -import 'package:marking_app/pages/homework_correction/index.dart'; import 'package:marking_app/pages/reports/index.dart'; import 'package:marking_app/provider/do_marking_provider.dart'; import 'package:marking_app/provider/upload_file_provider.dart'; -import 'package:marking_app/routes/RouterManager.dart'; import 'package:marking_app/utils/app_upgrade/UpdateDialog.dart'; import 'package:marking_app/utils/app_upgrade/model/UpdateAppEvent.dart'; import 'package:marking_app/common/model/sys/system_version.dart'; @@ -31,6 +29,8 @@ import 'package:marking_app/utils/index.dart'; import 'package:marking_app/utils/request/rest_client.dart'; import 'package:package_info/package_info.dart'; +import 'homework_correction/job_home.dart'; + class TheMainPage extends StatefulHookConsumerWidget { const TheMainPage({Key? key}) : super(key: key); @@ -49,7 +49,8 @@ class TheMainPageState extends ConsumerState with CommonMixin { final List _bodyList = [ const TheHomePage(), const TheMarking(), - const HomeworkCorrection(), + // const HomeworkCorrection(), + const JobHome(), const TheReport() ]; int tabIndex = 0; @@ -130,14 +131,8 @@ class TheMainPageState extends ConsumerState with CommonMixin { // String buildNumber = packageInfo.buildNumber; //小版本号 SystemVersion data = result.data!; - Map json = { - 'downloadPath': data.apkUrl, - 'version': data.version, - 'systemType': deviceType, - 'description': data.description - }; - UpdateAppEvent updateAppEvent = - UpdateAppEvent.fromJson(json, localVersion, deviceInfo, appName, packageName, typeName: 'systemType'); + Map json = {'downloadPath': data.apkUrl, 'version': data.version, 'systemType': deviceType, 'description': data.description}; + UpdateAppEvent updateAppEvent = UpdateAppEvent.fromJson(json, localVersion, deviceInfo, appName, packageName, typeName: 'systemType'); if (updateAppEvent.upgrade) { await UpdateDialog.showUpdateDialog(context, updateAppEvent); } From ee41ad7d1bb33e02e05551e0f63f1cfbf0adc2cc Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Thu, 11 Apr 2024 15:53:04 +0800 Subject: [PATCH 02/28] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BD=9C=E4=B8=9A?= =?UTF-8?q?=E9=A6=96=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/event_bus/job_home_refresh_bus.dart | 12 +++ .../lib/pages/homework_correction/index.dart | 66 +++++++------ .../pages/homework_correction/job_home.dart | 96 ++++++++++++++----- marking_app/lib/routes/RouterManager.dart | 72 ++++++-------- 4 files changed, 151 insertions(+), 95 deletions(-) create mode 100644 marking_app/lib/common/model/event_bus/job_home_refresh_bus.dart diff --git a/marking_app/lib/common/model/event_bus/job_home_refresh_bus.dart b/marking_app/lib/common/model/event_bus/job_home_refresh_bus.dart new file mode 100644 index 0000000..32f2485 --- /dev/null +++ b/marking_app/lib/common/model/event_bus/job_home_refresh_bus.dart @@ -0,0 +1,12 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'job_home_refresh_bus.g.dart'; + +@JsonSerializable() +class JobHomeRefreshBus extends Object { + JobHomeRefreshBus(); + + factory JobHomeRefreshBus.fromJson(Map srcJson) => _$JobHomeRefreshBusFromJson(srcJson); + + Map toJson() => _$JobHomeRefreshBusToJson(this); +} diff --git a/marking_app/lib/pages/homework_correction/index.dart b/marking_app/lib/pages/homework_correction/index.dart index 196ffe3..51b9c4e 100644 --- a/marking_app/lib/pages/homework_correction/index.dart +++ b/marking_app/lib/pages/homework_correction/index.dart @@ -7,6 +7,8 @@ * @Description: 阅卷主页 */ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -16,7 +18,9 @@ import 'package:flutter_easyrefresh/easy_refresh.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:marking_app/common/config/request_config.dart'; +import 'package:marking_app/common/model/event_bus/job_home_refresh_bus.dart'; import 'package:marking_app/common/model/job/job_task_item.dart'; +import 'package:marking_app/pages/common/event_bus_mixin.dart'; import 'package:marking_app/pages/homework_correction/components/new_version_of_homework/homework_tasks_view_item.dart'; import 'package:marking_app/provider/review_provider.dart'; import 'package:marking_app/routes/RouterManager.dart'; @@ -40,14 +44,7 @@ class HomeworkCorrection extends StatefulHookConsumerWidget { } class _HomeworkCorrectionState extends ConsumerState - with - CommonMixin, - TickerProviderStateMixin, - RefreshDataHandle, - AutomaticKeepAliveClientMixin { - @override - bool get wantKeepAlive => true; - + with CommonMixin, EventBusMixin, TickerProviderStateMixin, RefreshDataHandle { /* Tab控制器 */ late TabController _tabController; late TabController _tabController2; @@ -127,6 +124,7 @@ class _HomeworkCorrectionState extends ConsumerState _tabController.dispose(); _refreshController1.dispose(); _refreshController2.dispose(); + eventCancel(); super.dispose(); } @@ -152,8 +150,6 @@ class _HomeworkCorrectionState extends ConsumerState @override Widget build(BuildContext context) { - super.build(context); //调用super.build(返回值始终返回null,应将其忽略) - return AnnotatedRegion( value: const SystemUiOverlayStyle( systemNavigationBarColor: Color(0xFF000000), @@ -176,7 +172,19 @@ class _HomeworkCorrectionState extends ConsumerState child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Expanded(flex: 1, child: SizedBox()), + Expanded( + flex: 1, + child: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.only(left: 10.w), + child: InkWell( + onTap: () => easyThrottle('BACK_JOB_HOME', () => Navigator.of(context).pop()), + child: Icon( + Icons.arrow_back_ios_sharp, + size: 16.sp, + ), + ), + )), Expanded( flex: 4, child: Container( @@ -226,9 +234,7 @@ class _HomeworkCorrectionState extends ConsumerState child: quickText( '待批阅', size: 14.sp, - color: _tabIndex == 0 - ? Theme.of(context).primaryColor - : const Color.fromRGBO(80, 94, 110, 1), + color: _tabIndex == 0 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1), fontWeight: _tabIndex == 0 ? FontWeight.bold : null, ), ), @@ -246,9 +252,7 @@ class _HomeworkCorrectionState extends ConsumerState child: quickText( '已批阅', size: 14.sp, - color: _tabIndex == 1 - ? Theme.of(context).primaryColor - : const Color.fromRGBO(80, 94, 110, 1), + color: _tabIndex == 1 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1), fontWeight: _tabIndex == 1 ? FontWeight.bold : null, ), ), @@ -261,11 +265,9 @@ class _HomeworkCorrectionState extends ConsumerState flex: 1, child: InkWell( onTap: () { - RouterManager.router - .navigateTo(context, RouterManager.jobStudentGroupPath, transition: getTransition()); + RouterManager.router.navigateTo(context, RouterManager.jobStudentGroupPath, transition: getTransition()); }, - child: Icon(IconData(0xe63e, fontFamily: "AlibabaIcon"), - color: Color.fromRGBO(44, 48, 63, 1), size: 24.sp), + child: Icon(IconData(0xe63e, fontFamily: "AlibabaIcon"), color: Color.fromRGBO(44, 48, 63, 1), size: 24.sp), ), ), ], @@ -305,6 +307,9 @@ class _HomeworkCorrectionState extends ConsumerState data: markingDatas1, onLoad: onMyLoad, onRefresh: onMyRefresh, + eventFire: () { + eventFire(model: JobHomeRefreshBus()); + }, ), $EasyRefresh( controller: _refreshController2, @@ -313,6 +318,9 @@ class _HomeworkCorrectionState extends ConsumerState data: markingDatas2, onLoad: onMyLoad, onRefresh: onMyRefresh, + eventFire: () { + eventFire(model: JobHomeRefreshBus()); + }, ), ], ), @@ -334,6 +342,7 @@ Widget $easyRefresh({ required EasyRefreshController controller, required Future Function(EasyRefreshController controller, MarkingListParams params, int tab) onRefresh, required Future Function(EasyRefreshController controller, MarkingListParams params, int tab) onLoad, + required Function eventFire, required MarkingListParams params, required List data, required int tab, @@ -366,7 +375,10 @@ Widget $easyRefresh({ return HomeworkTasksViewItem( completed: completed, jobTaskItem: data[index], - call: () => controller.callRefresh(), + call: () { + controller.callRefresh(); + eventFire(); + }, ); }, itemCount: data.length, @@ -414,9 +426,7 @@ Widget $reviewedItem(BuildContext context, {required JobTaskItem jobTaskItem}) { alignment: Alignment.center, padding: EdgeInsets.only(left: 2.w), decoration: BoxDecoration( - color: jobTaskItem.markingTypeEnum.name == '作业' - ? const Color.fromRGBO(104, 136, 253, 1) - : const Color.fromRGBO(255, 175, 56, 1), + color: jobTaskItem.markingTypeEnum.name == '作业' ? const Color.fromRGBO(104, 136, 253, 1) : const Color.fromRGBO(255, 175, 56, 1), borderRadius: BorderRadius.only( topLeft: Radius.circular(14.r), topRight: Radius.circular(3.r), @@ -477,8 +487,7 @@ Widget $reviewedItem(BuildContext context, {required JobTaskItem jobTaskItem}) { onTap: () => easyThrottle('go_to_homework_report', () { RouterManager.router.navigateTo( context, - RouterManager.jobReportPagePath + - '?title=${Uri.encodeComponent(jobTaskItem.title)}&id=${jobTaskItem.id}', + RouterManager.jobReportPagePath + '?title=${Uri.encodeComponent(jobTaskItem.title)}&id=${jobTaskItem.id}', transition: getTransition(), ); }), @@ -521,8 +530,7 @@ Widget $theTabBar({required TabController controller, ValueChanged? onTap, if (customTime.endDate != null) { // print(customTime.startDate!.year == customTime.endDate!.year); if (!isPad() && customTime.startDate!.year == customTime.endDate!.year) { - customTimeStr = - customTime.startDate.toString().substring(5, 10) + '~${customTime.endDate.toString().substring(5, 10)}'; + customTimeStr = customTime.startDate.toString().substring(5, 10) + '~${customTime.endDate.toString().substring(5, 10)}'; } else { customTimeStr += '~${customTime.endDate?.toString().substring(0, 10)}'; } diff --git a/marking_app/lib/pages/homework_correction/job_home.dart b/marking_app/lib/pages/homework_correction/job_home.dart index 3fcb9db..9916e0a 100644 --- a/marking_app/lib/pages/homework_correction/job_home.dart +++ b/marking_app/lib/pages/homework_correction/job_home.dart @@ -2,10 +2,15 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:marking_app/common/mixin/common.dart'; +import 'package:marking_app/common/model/event_bus/job_home_refresh_bus.dart'; import 'package:marking_app/common/model/marking/marking_list_params.dart'; +import 'package:marking_app/pages/common/event_bus_mixin.dart'; +import 'package:marking_app/routes/RouterManager.dart'; import 'package:marking_app/utils/index.dart'; import 'package:marking_app/utils/my_text.dart'; +import 'package:badges/badges.dart' as badges; + import '../../utils/my_future_builder.dart'; class JobHome extends StatefulWidget { @@ -15,16 +20,16 @@ class JobHome extends StatefulWidget { State createState() => _JobHomeState(); } -class _JobHomeState extends State with CommonMixin, AutomaticKeepAliveClientMixin { +class _JobHomeState extends State with CommonMixin, EventBusMixin, AutomaticKeepAliveClientMixin { @override bool get wantKeepAlive => true; - late Future _future; + late Future _future; List entrances = [ EntranceModel( title: '作业批阅', image: '', - navigationUrl: '', + navigationUrl: RouterManager.jobMainListPagePath, ), EntranceModel( title: '学生历史作业', @@ -56,19 +61,32 @@ class _JobHomeState extends State with CommonMixin, AutomaticKeepAliveC @override void initState() { _future = getData(); + eventOn(callback: (JobHomeRefreshBus item) { + _future = getData(); + toUpState(setState, () {}, mounted); + }); super.initState(); } - Future getData() async { - var _client = await getClient(); - var _result = await _client.getJobsByPage(MarkingListParams( - isFinish: false, - page: 1, - limit: 1, - pageType: 0, - )); - if (_result == null) return 0; - return _result.data?.total ?? 0; + @override + void dispose() { + eventCancel(); + super.dispose(); + } + + Future getData() async { + try { + var _client = await getClient(); + var _result = await _client.getJobsByPage(MarkingListParams( + isFinish: false, + page: 1, + limit: 1, + pageType: 0, + )); + return _result.data?.total ?? 0; + } catch (e) { + return 0; + } } @override @@ -97,7 +115,7 @@ class _JobHomeState extends State with CommonMixin, AutomaticKeepAliveC _future = getData(); toUpState(setState, () {}, mounted); }, - child: MyFutureBuilder.buildFutureBuilderOfSingleInstance(context, _future, (data) { + child: MyFutureBuilder.buildFutureBuilderOfSingleInstance(context, _future, (data) { if (data == null) return Center( child: Container( @@ -112,22 +130,50 @@ class _JobHomeState extends State with CommonMixin, AutomaticKeepAliveC ); return Container( + padding: EdgeInsets.symmetric(vertical: 40.h, horizontal: 20.w), child: GridView( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, - mainAxisSpacing: 10.r, - crossAxisSpacing: 10.r, - childAspectRatio: 556 / 112, + mainAxisSpacing: 24.r, + crossAxisSpacing: 24.r, + childAspectRatio: 556 / 200, ), children: entrances.map((e) { - return Container( - alignment: Alignment.center, - child: Row( - children: [ - quickText(e.title), - ], - ), - ); + bool isJob = e.title == '作业批阅'; + + return InkWell( + onTap: () => easyThrottle('GO_TO_JOB_HOME_NAVIGATION', () { + RouterManager.router.navigateTo(context, e.navigationUrl, transition: getTransition()); + }), + child: badges.Badge( + showBadge: isJob && data > 0, + ignorePointer: false, + badgeContent: quickText(data, color: Colors.white), + badgeAnimation: badges.BadgeAnimation.rotation( + animationDuration: Duration(seconds: 1), + colorChangeAnimationDuration: Duration(seconds: 1), + loopAnimation: false, + curve: Curves.fastOutSlowIn, + colorChangeAnimationCurve: Curves.easeInCubic, + ), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(6.r)), + border: Border.all( + width: 0.5.w, + color: Color.fromARGB(255, 219, 226, 250), + ), + ), + alignment: Alignment.center, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // Image(image: e.image), + quickText(e.title, size: 12.sp), + ], + ), + ), + )); }).toList(), ), ); diff --git a/marking_app/lib/routes/RouterManager.dart b/marking_app/lib/routes/RouterManager.dart index 21516c5..0470c24 100644 --- a/marking_app/lib/routes/RouterManager.dart +++ b/marking_app/lib/routes/RouterManager.dart @@ -7,13 +7,12 @@ * @Description: 路由 */ -import 'dart:convert'; - import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'package:marking_app/common/model/enum/marking_list_type.dart'; import 'package:marking_app/pages/common/startUpPage.dart'; import 'package:marking_app/pages/homework_correction/do_papers_job_exam.dart'; +import 'package:marking_app/pages/homework_correction/index.dart'; import 'package:marking_app/pages/homework_correction/job_personal_detail.dart'; import 'package:marking_app/pages/homework_correction/job_priority_review_set.dart'; import 'package:marking_app/pages/homework_correction/job_report.dart'; @@ -64,6 +63,8 @@ class RouterManager { static const String jobListParticipateInClassPath = '/job/list/participateInClass'; // 作业 ==> 收藏页面 static const String jobFavoritePagePath = '/job/favorite/index'; +// 作业 ==> 列表页面 + static const String jobMainListPagePath = '/job/mainList/index'; static const String reportClassTeacherPath = 'report/details/reportClassTeacher'; static const String reportSubjectTeacherPath = 'report/details/reportSubjectTeacher'; @@ -100,18 +101,14 @@ class RouterManager { } // 启动页 - static final _startUpPageHandler = - Handler(handlerFunc: (BuildContext? context, Map> params) => const StartUpPage()); + static final _startUpPageHandler = Handler(handlerFunc: (BuildContext? context, Map> params) => const StartUpPage()); // 主页 - static final _mainPageHandler = - Handler(handlerFunc: (BuildContext? context, Map> params) => const TheMainPage()); + static final _mainPageHandler = Handler(handlerFunc: (BuildContext? context, Map> params) => const TheMainPage()); // 登录页 - static final _loginPageHandler = - Handler(handlerFunc: (BuildContext? context, Map> params) => const TheLogin()); + static final _loginPageHandler = Handler(handlerFunc: (BuildContext? context, Map> params) => const TheLogin()); // 阅卷进度页面 static final _progressPageHandler = Handler( - handlerFunc: (BuildContext? context, Map> params) => - Progress(int.parse(params['examSubjectId']![0]), params['name']![0])); + handlerFunc: (BuildContext? context, Map> params) => Progress(int.parse(params['examSubjectId']![0]), params['name']![0])); // 回评页面 static final _reviewPageHandler = Handler(handlerFunc: (BuildContext? context, Map> params) { int markingUserId = int.parse(params['markingUserId']![0]); @@ -130,11 +127,8 @@ class RouterManager { // 回评异常页面 static final _reviewAbnormalPageHandler = Handler( - handlerFunc: (BuildContext? context, Map> params) => ProgressAbnormal( - int.parse(params['examSubjectId']![0]), - params['markingId']![0], - params['name']![0], - params['questionNum']![0])); + handlerFunc: (BuildContext? context, Map> params) => + ProgressAbnormal(int.parse(params['examSubjectId']![0]), params['markingId']![0], params['name']![0], params['questionNum']![0])); // 阅卷页面 static final _markingDoPageHandler = Handler(handlerFunc: (BuildContext? context, Map> params) { try { @@ -176,8 +170,7 @@ class RouterManager { } }); // 批阅作业页面 - static final _markingHomeworkDoPageHandler = - Handler(handlerFunc: (BuildContext? context, Map> params) { + static final _markingHomeworkDoPageHandler = Handler(handlerFunc: (BuildContext? context, Map> params) { try { int taskId = int.parse(params['taskId']![0]); int jobId = int.parse(params['jobId']![0]); @@ -221,8 +214,7 @@ class RouterManager { handlerFunc: (BuildContext? context, Map> params) => const OhterPage(), ); - static final _reportClassTeacherPageHandler = - Handler(handlerFunc: (BuildContext? context, Map> params) { + static final _reportClassTeacherPageHandler = Handler(handlerFunc: (BuildContext? context, Map> params) { int examId = int.parse(params['examId']![0]); return ReportClassTeacher(examId: examId); @@ -292,7 +284,7 @@ class RouterManager { if (params['gradeId'] != null && params['gradeId']?[0] != null && params['gradeId']![0] != 'null') { gradeId = int.parse(params['gradeId']![0]); } - return QuickDataCheckPage(jobId: jobId, className: className,gradeName:gradeName,schoolId:schoolId,gradeId:gradeId); + return QuickDataCheckPage(jobId: jobId, className: className, gradeName: gradeName, schoolId: schoolId, gradeId: gradeId); }, ); @@ -310,7 +302,7 @@ class RouterManager { handlerFunc: (BuildContext? context, Map> params) { String groupId = params['groupId']![0]; String title = params['title']![0]; - return JobPriorityReviewSet(groupId: groupId,title:title); + return JobPriorityReviewSet(groupId: groupId, title: title); }, ); @@ -334,7 +326,7 @@ class RouterManager { if (params['gradeId'] != null && params['gradeId']?[0] != null && params['gradeId']![0] != 'null') { gradeId = int.parse(params['gradeId']![0]); } - return JobFavorite(jobId: jobId, gradeId: gradeId, schoolId: schoolId, className: className,jobName:jobName); + return JobFavorite(jobId: jobId, gradeId: gradeId, schoolId: schoolId, className: className, jobName: jobName); }, ); @@ -343,14 +335,19 @@ class RouterManager { handlerFunc: (BuildContext? context, Map> params) { String studentName = params['studentName']![0]; int studentId = int.parse(params['studentId']![0]); - return JobPersonalDetail(studentId: studentId,studentName:studentName); + return JobPersonalDetail(studentId: studentId, studentName: studentName); }, ); + // 优先配置个人详情 + static final _jobMainListPathHandler = Handler( + handlerFunc: (BuildContext? context, Map> params) => HomeworkCorrection(), + ); + // 学生报告详情 static final _reportCardDialogPathHandler = Handler( handlerFunc: (BuildContext? context, Map> params) { - /* String studentName = params['studentName']![0]; + /* String studentName = params['studentName']![0]; int studentId = int.parse(params['studentId']![0]); return ReportCardDialog(studentId: studentId,studentName:studentName);*/ }, @@ -358,7 +355,7 @@ class RouterManager { // 学生历史报告 static final _reportHistoryPathHandler = Handler( handlerFunc: (BuildContext? context, Map> params) { - /* String studentName = params['studentName']![0]; + /* String studentName = params['studentName']![0]; int studentId = int.parse(params['studentId']![0]);*/ return ReportHistory(); }, @@ -380,35 +377,28 @@ class RouterManager { router.define(markingReviewPath, handler: _reviewPageHandler, transitionType: TransitionType.material); router.define(markingJobReviewPath, handler: _reviewJobPageHandler, transitionType: TransitionType.material); router.define(markingDoPath, handler: _markingDoPageHandler, transitionType: TransitionType.material); - router.define(markingHomeworkDoPath, - handler: _markingHomeworkDoPageHandler, transitionType: TransitionType.material); - router.define(markingReviewAbnormalPath, - handler: _reviewAbnormalPageHandler, transitionType: TransitionType.material); + router.define(markingHomeworkDoPath, handler: _markingHomeworkDoPageHandler, transitionType: TransitionType.material); + router.define(markingReviewAbnormalPath, handler: _reviewAbnormalPageHandler, transitionType: TransitionType.material); router.define(agreementPath, handler: _agreementPageHandler, transitionType: TransitionType.material); router.define(ohterMainPagePath, handler: _ohterMainPageHandler, transitionType: TransitionType.material); - router.define(reportClassTeacherPath, - handler: _reportClassTeacherPageHandler, transitionType: TransitionType.material); - router.define(reportSubjectTeacherPath, - handler: _reportSubjectTeacherPageHandler, transitionType: TransitionType.material); - router.define(reportPersonalSubjectPath, - handler: _reportPersonalSubjectPageHandler, transitionType: TransitionType.material); + router.define(reportClassTeacherPath, handler: _reportClassTeacherPageHandler, transitionType: TransitionType.material); + router.define(reportSubjectTeacherPath, handler: _reportSubjectTeacherPageHandler, transitionType: TransitionType.material); + router.define(reportPersonalSubjectPath, handler: _reportPersonalSubjectPageHandler, transitionType: TransitionType.material); router.define(userMinePath, handler: _userMinePageHandler, transitionType: TransitionType.material); router.define(reportDetailPath, handler: _reportDetailPath, transitionType: TransitionType.material); router.define(jobReportPagePath, handler: _jobReportPageHandler, transitionType: TransitionType.material); router.define(jobExamPagePath, handler: _jobExamPageHandler, transitionType: TransitionType.material); - router.define(jobListParticipateInClassPath, - handler: _jobListParticipateInClassHandler, transitionType: TransitionType.material); + router.define(jobListParticipateInClassPath, handler: _jobListParticipateInClassHandler, transitionType: TransitionType.material); router.define(quickDataCheckPath, handler: _quickDataCheckPageHandler, transitionType: TransitionType.material); - router.define(quickCheckPersonalPath, - handler: _quickCheckPersonalPageHandler, transitionType: TransitionType.material); - router.define(jobPriorityReviewSetPath, - handler: _jobPriorityReviewSetPageHandler, transitionType: TransitionType.material); + router.define(quickCheckPersonalPath, handler: _quickCheckPersonalPageHandler, transitionType: TransitionType.material); + router.define(jobPriorityReviewSetPath, handler: _jobPriorityReviewSetPageHandler, transitionType: TransitionType.material); router.define(jobStudentGroupPath, handler: _jobStudentGroupPageHandler, transitionType: TransitionType.material); router.define(jobFavoritePagePath, handler: _jobFavoritePagePathHandler, transitionType: TransitionType.material); router.define(jobPersonalDetailPath, handler: _jobPersonalDetailPathHandler, transitionType: TransitionType.material); router.define(reportCardDialogPath, handler: _reportCardDialogPathHandler, transitionType: TransitionType.material); router.define(reportHistoryPath, handler: _reportHistoryPathHandler, transitionType: TransitionType.material); + router.define(jobMainListPagePath, handler: _jobMainListPathHandler, transitionType: TransitionType.material); // getTransition() From 74c814830527bdfeeee50b14c760bec9836f405b Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Thu, 11 Apr 2024 15:53:31 +0800 Subject: [PATCH 03/28] no message --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index bab1ac1..c1a9ebb 100644 --- a/.gitignore +++ b/.gitignore @@ -214,3 +214,4 @@ marking_app/lib/pages/homework_correction/job_personal_detail.g.dart marking_app/lib/common/model/event_bus/jobs/job_do_papers_submit_check_switch_bus.g.dart marking_app/lib/common/model/event_bus/jobs/job_do_synchro_tab.g.dart marking_app/lib/pages/homework_correction/widget/top_count.g.dart +marking_app/lib/common/model/event_bus/job_home_refresh_bus.g.dart From 991ec9310e2b9c53a43d0b81a0607ca221ed4a9c Mon Sep 17 00:00:00 2001 From: machuanyu <840649825@qq.com> Date: Thu, 11 Apr 2024 17:15:27 +0800 Subject: [PATCH 04/28] =?UTF-8?q?=E7=9F=A5=E8=AF=86=E7=82=B9=E6=8E=8C?= =?UTF-8?q?=E6=8F=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- marking_app/assets/images/right_icon_blue.png | Bin 0 -> 293 bytes .../model/job/job_knowledge_points.dart | 29 ++ .../job/job_knowledge_points_detail.dart | 38 ++ .../lib/pages/homework_correction/index.dart | 12 +- .../job_knowledge_points.dart | 487 ++++++++++++++++++ .../job_knowledge_points_detail.dart | 486 +++++++++++++++++ .../job_personal_detail.dart | 1 + .../quick_check_personal.dart | 4 +- marking_app/lib/routes/RouterManager.dart | 24 + marking_app/lib/utils/common_utils.dart | 22 + 10 files changed, 1098 insertions(+), 5 deletions(-) create mode 100644 marking_app/assets/images/right_icon_blue.png create mode 100644 marking_app/lib/common/model/job/job_knowledge_points.dart create mode 100644 marking_app/lib/common/model/job/job_knowledge_points_detail.dart create mode 100644 marking_app/lib/pages/homework_correction/job_knowledge_points.dart create mode 100644 marking_app/lib/pages/homework_correction/job_knowledge_points_detail.dart diff --git a/marking_app/assets/images/right_icon_blue.png b/marking_app/assets/images/right_icon_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..87bb071aec1b626ebed808d8a9ef746f83d6abcc GIT binary patch literal 293 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9E$svykh8Km+7D9BhG zh($ literal 0 HcmV?d00001 diff --git a/marking_app/lib/common/model/job/job_knowledge_points.dart b/marking_app/lib/common/model/job/job_knowledge_points.dart new file mode 100644 index 0000000..8e23efb --- /dev/null +++ b/marking_app/lib/common/model/job/job_knowledge_points.dart @@ -0,0 +1,29 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'job_knowledge_points.g.dart'; + + +@JsonSerializable() +class KnowledgePoints extends Object { + + @JsonKey(name: 'knowledgeId') + int knowledgeId; + + @JsonKey(name: 'knowledgeName') + String knowledgeName; + + @JsonKey(name: 'correctRate') + int correctRate; + + @JsonKey(name: 'count') + int count; + + KnowledgePoints(this.knowledgeId,this.knowledgeName,this.correctRate,this.count,); + + factory KnowledgePoints.fromJson(Map srcJson) => _$KnowledgePointsFromJson(srcJson); + + Map toJson() => _$KnowledgePointsToJson(this); + +} + + diff --git a/marking_app/lib/common/model/job/job_knowledge_points_detail.dart b/marking_app/lib/common/model/job/job_knowledge_points_detail.dart new file mode 100644 index 0000000..4009d97 --- /dev/null +++ b/marking_app/lib/common/model/job/job_knowledge_points_detail.dart @@ -0,0 +1,38 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'job_knowledge_points_detail.g.dart'; + + +@JsonSerializable() +class KnowledgePointsDetail extends Object { + + @JsonKey(name: 'jobId') + int jobId; + + @JsonKey(name: 'jobName') + String jobName; + + @JsonKey(name: 'publishTime') + String publishTime; + + @JsonKey(name: 'questionId') + int questionId; + + @JsonKey(name: 'questionNo') + String questionNo; + + @JsonKey(name: 'sectionId') + int sectionId; + + @JsonKey(name: 'correctRate') + int correctRate; + + KnowledgePointsDetail(this.jobId,this.jobName,this.publishTime,this.questionId,this.questionNo,this.sectionId,this.correctRate,); + + factory KnowledgePointsDetail.fromJson(Map srcJson) => _$KnowledgePointsDetailFromJson(srcJson); + + Map toJson() => _$KnowledgePointsDetailToJson(this); + +} + + diff --git a/marking_app/lib/pages/homework_correction/index.dart b/marking_app/lib/pages/homework_correction/index.dart index bbf528d..8341bfc 100644 --- a/marking_app/lib/pages/homework_correction/index.dart +++ b/marking_app/lib/pages/homework_correction/index.dart @@ -272,13 +272,19 @@ class _HomeworkCorrectionState extends ConsumerState ), ), - /* Row( + /* Row( children: [ InkWell( onTap: (){ - + RouterManager.router.navigateTo( + context, + RouterManager.jobKnowledgePointsPath, + transition: getTransition(), + ); }, - child: Text('历史作业'), + child: SizedBox( + height: 30.r, + child: Text('知识点掌握')), ), ], ),*/ diff --git a/marking_app/lib/pages/homework_correction/job_knowledge_points.dart b/marking_app/lib/pages/homework_correction/job_knowledge_points.dart new file mode 100644 index 0000000..dd410b2 --- /dev/null +++ b/marking_app/lib/pages/homework_correction/job_knowledge_points.dart @@ -0,0 +1,487 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:functional_widget_annotation/functional_widget_annotation.dart'; +import 'package:marking_app/common/mixin/common.dart'; +import 'package:marking_app/common/model/common/base_structure_result.dart'; +import 'package:marking_app/common/model/job/job_knowledge_points.dart'; +import 'package:marking_app/common/model/job/job_student_history.dart'; +import 'package:marking_app/components/ReturnToHomepage.dart'; +import 'package:marking_app/pages/homework_correction/widget/personal_detail_topbar.dart'; +import 'package:marking_app/routes/RouterManager.dart'; +import 'package:marking_app/utils/easy_refresh/MyEmptyWidget.dart'; +import 'package:marking_app/utils/index.dart'; +import 'package:marking_app/utils/my_text.dart'; +import 'package:marking_app/utils/request/rest_client.dart'; +import 'package:percent_indicator/percent_indicator.dart'; +import 'package:syncfusion_flutter_datepicker/datepicker.dart'; + +part 'job_knowledge_points.g.dart'; + +class JobKnowledgePoints extends StatefulWidget { + + const JobKnowledgePoints({Key? key,}) : super(key: key); + + @override + _JobKnowledgePointsState createState() => _JobKnowledgePointsState(); +} + +class _JobKnowledgePointsState extends State with CommonMixin, TickerProviderStateMixin { + @override + int page = 1; + int pageSize = 10; + int totalPages = 0; + late TabController tabController; + String startDataTime = CommonUtils.getWeekStartDate().toString().substring(0, 10); + String endDataTime = CommonUtils.getWeekEndDate().toString().substring(0, 10); + String customTimeStr = '自定义'; + List dataList = []; + late final EasyRefreshController refreshController; + + //文本输入框控制器 + late final TextEditingController textController; + int studentId = 0; + + @override + void initState() { + super.initState(); + textController = TextEditingController(); + + refreshController = EasyRefreshController(); + tabController = TabController(length: 3, vsync: this); + EasyLoading.show(status: 'loading...'); + getList(); + } + + @override + void dispose() { + super.dispose(); + tabController.dispose(); + textController.dispose(); + } + + void getList() async { + print('startDataTime=$startDataTime'); + print('endDataTime=$endDataTime'); + RestClient _client = await getClient(); + BaseStructureResult> res = + await _client.getKnowledgeReport(textController.text); + if (res.success) { + setState(() { + if (page == 1) { + dataList = res.data!; + } else { + dataList = [...dataList, ...res.data!]; + } + + // totalPages = res.data!.pagedList.totalPages; + }); + } + + EasyLoading.dismiss(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Color.fromRGBO(245, 245, 245, 1), + appBar: AppBar( + backgroundColor: Colors.white, + title: Text('知识点掌握', style: TextStyle(fontSize: 14.sp, color: Color(0xFF333333))), + centerTitle: true, + leading: IconButton( + icon: Icon(Icons.arrow_back_ios, color: Colors.black), + onPressed: () => Navigator.of(context).pop(), + ), + actions: [ + ReturnToHomepage(), + ], + elevation: 0, + ), + body: Column( + children: [ + Container( + margin: EdgeInsets.all(15.r), + height: 30.r, + child: Row( + children: [ + Expanded( + child: Container( + padding: EdgeInsets.only(left: 10.r,right: 10.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6.r), + border: Border.all(width: 1.r,color: Color(0xFFDDDDDD)), + color: Colors.white, + ), + child: TextField( + controller: textController, + textInputAction: TextInputAction.next, + style: TextStyle( + color: const Color.fromRGBO(80, 87, 103, 1), + fontSize: 10.sp, + ), + decoration: InputDecoration( + hintText: "请输入知识点名称", + hintStyle: TextStyle(fontSize: 10.sp, color: const Color.fromRGBO(153, 153, 153, 1)), + labelStyle: TextStyle(fontSize: 10.sp, color: const Color.fromRGBO(148, 163, 182, 1)), + border: InputBorder.none, + ), + ), + ), + ), + SizedBox(width: 10.r,), + InkWell( + onTap: (){ + page = 1; + setState(() {}); + getList(); + }, + child: Container( + width: 50.r, + height: 30.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4.r), + color: Color(0xFF6888FD), + ), + child:Center( + child: Text('查询',style: TextStyle(fontSize: 12.sp,color: Colors.white),), + ), + ), + ) + ], + ), + ), + + + jobConditionFilter(context, + controller: tabController, + customTimeStr: customTimeStr, + customTime: tabController.index != 3 || + ((endDataTime == null || endDataTime == '') && (startDataTime == null || startDataTime == '')) + ? null + : PickerDateRange( + startDataTime == null || startDataTime == '' ? null : DateTime.parse(startDataTime!), + endDataTime == null || endDataTime == '' ? null : DateTime.parse(endDataTime!), + ), onTimeFilter: (String? startTime, String? endTime) { + EasyLoading.show(status: 'loading...'); + if (startTime == null && endTime == null) { + if (tabController.index == 3) { + tabController.animateTo(0); + } + startDataTime = ''; + endDataTime = ''; + customTimeStr = '自定义'; + } else { + startDataTime = startTime != null ? startTime : ''; + endDataTime = endTime != null ? endTime : ''; + } + page = 1; + setState(() {}); + getList(); + // _refreshController2.callRefresh(); + }, refreshTime: (value) { + if (value != null && value.startDate != null) { + customTimeStr = value.startDate?.toString().substring(0, 10) ?? ''; + setState(() {}); + if (value.endDate != null) { + if (!isPad() && value.startDate!.year == value.endDate!.year) { + customTimeStr = + value.startDate.toString().substring(5, 10) + '~${value.endDate.toString().substring(5, 10)}'; + setState(() {}); + } else { + customTimeStr = '$customTimeStr~${value.endDate?.toString().substring(0, 10)}'; + setState(() {}); + } + } + } + }), + Expanded( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 10.r), + child: EasyRefresh( + firstRefresh: false, + taskIndependence: true, + controller: refreshController, + header: MaterialHeader(), + footer: TaurusFooter(), + onRefresh: () async { + setState(() { + page = 1; + }); + getList(); + }, + onLoad: () async { + if (page < totalPages) { + setState(() { + page += 1; + }); + getList(); + } + }, + child: dataList.length > 0 + ? ListView.builder( + itemCount: dataList.length, + itemBuilder: (context, index) { + KnowledgePoints item = dataList[index]; + return InkWell( + onTap: () { + RouterManager.router.navigateTo( + context, + RouterManager.jobKnowledgePointsDetailPath + + '?knowledgeName=${Uri.encodeComponent(item.knowledgeName)}&knowledgeId=${item.knowledgeId}', + transition: getTransition(), + ); + }, + child: Container( + margin: EdgeInsets.symmetric(vertical: 5.r, horizontal: 14.r), + padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 10.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(10.r)), + color: Colors.white), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: Text( + item.knowledgeName, + style: TextStyle(fontSize: 14.sp, color: Color(0xFF505050)), + )), + + Container( + width: 49.r, + height: 22.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(20.r)), + border: Border.all(width: 1.r, color: Color(0xFF6888FD)), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + '2次', + style: TextStyle(fontSize: 10.sp, color: Color(0xFF6888FD)), + ), + Image.asset('assets/images/right_icon_blue.png',width: 8.r,height: 8.r,), + ], + ), + ), + ], + ), + SizedBox(height: 10.r,), + progressBar(context, + title: '正确率:', + color: Color(0xFF90E0BE), + percent: item.correctRate / 100, + padingEdg: EdgeInsets.zero, + marginEdg: EdgeInsets.only(top: 8.h)), + ], + ), + ), + ); + }) + : MyEmptyWidget(), + ), + ), + ), + ], + ), + ); + } +} + +@swidget +Widget progressBar( + BuildContext context, { + double? fontSize, + double? lineHeight, + required String title, + required Color color, + required double percent, + required EdgeInsets padingEdg, + required EdgeInsets marginEdg, + }) { + var percentStr = '${doubleToStringAsFixed(percent * 100)}%'; + fontSize ??= 10.sp; + lineHeight ??= 8.h; + return Container( + margin: marginEdg, + padding: padingEdg, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (title == '总正确率:') quickText('确率', color: Colors.transparent, size: fontSize), + quickText(title, color: Color(0xFF8B8B8B), size: fontSize), + Expanded( + flex: 1, + child: Container( + child: Row( + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.r), + /* boxShadow: [ + BoxShadow( + color: color, + spreadRadius: 0.6, + blurRadius: 3, + offset: Offset(0, 0), + ), + ],*/ + ), + child: LinearPercentIndicator( + padding: EdgeInsets.zero, + animation: true, + lineHeight: lineHeight, + animationDuration: 2500, + percent: percent, + /* center: Text( + percentStr, + style: TextStyle(color: Colors.white, fontSize: 4.5.sp), + ),*/ + // linearStrokeCap: LinearStrokeCap.butt, + progressColor: color, + backgroundColor: Color(0xFFE8E8E8), + barRadius: Radius.circular(10.r), + // linearGradient: LinearGradient( + // tileMode: TileMode.mirror, + // stops: [0.0, 1.0], + // colors: [color.withOpacity(0.1), color], + // ), + ), + ), + ), + SizedBox(width: 4.w), + quickText(percentStr, size: fontSize, color: Color(0xFF464646)) + ], + ), + ), + ), + ], + ), + ); +} + +/// 已完成作业条件筛选栏 +@hwidget +Widget jobConditionFilter(BuildContext context, + {required TabController controller, + PickerDateRange? customTime, + required Function refreshTime, + required String customTimeStr, + required Function(String? startTime, String? endTime) onTimeFilter}) { + var customTimeState = PickerDateRange(null, null); + if (customTime != null) { + customTimeState = PickerDateRange(customTime!.startDate != null ? customTime!.startDate : null, + customTime!.endDate != null ? customTime!.endDate : null); + } + + DateTime getMonthStartDate() { + DateTime now = DateTime.now(); + return DateTime(now.year, now.month, 1); // 获取当前月份的第一天 + } + + DateTime getMonthEndDate() { + DateTime now = DateTime.now(); + int nextMonth = now.month + 1; + if (nextMonth > 12) { + nextMonth = 1; + now = now.add(Duration(days: 31 - now.day)); // 跨年了,所以加到当前月的最后一天 + } else { + now = now.add(Duration(days: DateTime(now.year, nextMonth, 0).day - now.day)); // 加到下个月的第一天的前一天,即本月最后一天 + } + return now; + } + + return Container( + // height: 39.h, + // padding: EdgeInsets.only(left: 4.w, right: 12.w), + decoration: BoxDecoration( + color: Color.fromRGBO(244, 244, 244, 1), + // border: Border(bottom: BorderSide(color: Color.fromRGBO(204, 204, 204, 1), width: 1)), + ), + child: Container( + alignment: Alignment.centerLeft, + decoration: BoxDecoration( + border: Border(bottom: BorderSide(width: 1.r,color: Color(0xFFCCCCCC))) + ), + child: TabBar( + controller: controller, + unselectedLabelStyle: TextStyle(fontSize: 12.sp, color: const Color.fromRGBO(102, 102, 102, 1)), + labelStyle: TextStyle( + fontSize: 12.sp, + fontWeight: FontWeight.bold, + color: Color.fromRGBO(116, 145, 253, 1), + ), + isScrollable: true, + labelColor: Color(0xFF6888FD), + unselectedLabelColor: Color(0xFF666666), + padding: EdgeInsets.symmetric(horizontal: 14.r), + // indicatorSize: TabBarIndicatorSize.label, // 设置指示器高度和标签一样高 + onTap: (int val) async { + switch (val) { + case 0: // 近一周 + onTimeFilter( + CommonUtils.getWeekStartDate().toString().substring(0, 10), + CommonUtils.getWeekEndDate().toString().substring(0, 10), + ); + break; + case 1: // 近一个月 + onTimeFilter( + getMonthStartDate().toString().substring(0, 10), + getMonthEndDate().toString().substring(0, 10), + ); + break; + default: // 自定义 + var dialogData = await showDialog( + context: context, + builder: (BuildContext context1) { + return Center( + child: Container( + color: Colors.white, + width: isPad() ? ScreenUtil().screenWidth / 2 : ScreenUtil().screenWidth / 1.3, + height: ScreenUtil().screenHeight / 2, + child: SfDateRangePicker( + showActionButtons: true, + confirmText: '确定', + cancelText: '取消', + onSubmit: (p0) { + print(p0); + Navigator.of(context1).pop(p0); + refreshTime(p0); + }, + onCancel: () { + Navigator.of(context1).pop(); + }, + selectionMode: DateRangePickerSelectionMode.range, + initialSelectedRange: customTimeState, + ), + ), + ); + }); + // startDate: 2024-03-04 18:47:00.117958, endDate: 2024-03-11 18:47:00.117986 + // if (dialogData != null && (dialogData.startDate != null || dialogData.endDate != null)) {} + onTimeFilter( + dialogData?.startDate?.toString().substring(0, 10), + dialogData?.endDate?.toString().substring(0, 10), + ); + customTimeState = dialogData!; + } + }, + tabs: [ + const Tab(text: '近一周'), + const Tab(text: '近一月'), + Tab(text: customTimeStr), + ], + ), + ), + ); +} diff --git a/marking_app/lib/pages/homework_correction/job_knowledge_points_detail.dart b/marking_app/lib/pages/homework_correction/job_knowledge_points_detail.dart new file mode 100644 index 0000000..f5be7a1 --- /dev/null +++ b/marking_app/lib/pages/homework_correction/job_knowledge_points_detail.dart @@ -0,0 +1,486 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:functional_widget_annotation/functional_widget_annotation.dart'; +import 'package:marking_app/common/mixin/common.dart'; +import 'package:marking_app/common/model/common/base_structure_result.dart'; +import 'package:marking_app/common/model/job/job_knowledge_points.dart'; +import 'package:marking_app/common/model/job/job_knowledge_points_detail.dart'; +import 'package:marking_app/common/model/job/job_student_history.dart'; +import 'package:marking_app/components/ReturnToHomepage.dart'; +import 'package:marking_app/pages/homework_correction/widget/personal_detail_topbar.dart'; +import 'package:marking_app/routes/RouterManager.dart'; +import 'package:marking_app/utils/easy_refresh/MyEmptyWidget.dart'; +import 'package:marking_app/utils/index.dart'; +import 'package:marking_app/utils/my_text.dart'; +import 'package:marking_app/utils/request/rest_client.dart'; +import 'package:percent_indicator/percent_indicator.dart'; +import 'package:syncfusion_flutter_datepicker/datepicker.dart'; + + +class JobKnowledgePointsDetail extends StatefulWidget { +final String knowledgeName; +final int knowledgeId; + const JobKnowledgePointsDetail({Key? key,required this.knowledgeName,required this.knowledgeId}) : super(key: key); + + @override + _JobKnowledgePointsDetailState createState() => _JobKnowledgePointsDetailState(); +} + +class _JobKnowledgePointsDetailState extends State with CommonMixin, TickerProviderStateMixin { + @override + int page = 1; + int pageSize = 10; + int totalPages = 0; + late TabController tabController; + String startDataTime = CommonUtils.getWeekStartDate().toString().substring(0, 10); + String endDataTime = CommonUtils.getWeekEndDate().toString().substring(0, 10); + String customTimeStr = '自定义'; + List dataList = []; + late final EasyRefreshController refreshController; + + //文本输入框控制器 + late final TextEditingController textController; + int studentId = 0; + + @override + void initState() { + super.initState(); + textController = TextEditingController(); + + refreshController = EasyRefreshController(); + tabController = TabController(length: 3, vsync: this); + EasyLoading.show(status: 'loading...'); + getList(); + } + + @override + void dispose() { + super.dispose(); + tabController.dispose(); + textController.dispose(); + } + + void getList() async { + RestClient _client = await getClient(); + BaseStructureResult> res = + await _client.getKnowledgeReportDetail(widget.knowledgeId); + if (res.success) { + setState(() { + if (page == 1) { + dataList = res.data!; + } else { + dataList = [...dataList, ...res.data!]; + } + + // totalPages = res.data!.pagedList.totalPages; + }); + } + + EasyLoading.dismiss(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Color.fromRGBO(245, 245, 245, 1), + appBar: AppBar( + backgroundColor: Colors.white, + title: Text(widget.knowledgeName, style: TextStyle(fontSize: 14.sp, color: Color(0xFF333333))), + centerTitle: true, + leading: IconButton( + icon: Icon(Icons.arrow_back_ios, color: Colors.black), + onPressed: () => Navigator.of(context).pop(), + ), + actions: [ + ReturnToHomepage(), + ], + elevation: 0, + ), + body: Column( + children: [ + Container( + margin: EdgeInsets.all(15.r), + height: 30.r, + child: Row( + children: [ + Expanded( + child: Container( + padding: EdgeInsets.only(left: 10.r,right: 10.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6.r), + border: Border.all(width: 1.r,color: Color(0xFFDDDDDD)), + color: Colors.white, + ), + child: TextField( + controller: textController, + textInputAction: TextInputAction.next, + style: TextStyle( + color: const Color.fromRGBO(80, 87, 103, 1), + fontSize: 10.sp, + ), + decoration: InputDecoration( + hintText: "请输入知识点名称", + hintStyle: TextStyle(fontSize: 10.sp, color: const Color.fromRGBO(153, 153, 153, 1)), + labelStyle: TextStyle(fontSize: 10.sp, color: const Color.fromRGBO(148, 163, 182, 1)), + border: InputBorder.none, + ), + ), + ), + ), + SizedBox(width: 10.r,), + InkWell( + onTap: (){ + page = 1; + setState(() {}); + getList(); + }, + child: Container( + width: 50.r, + height: 30.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4.r), + color: Color(0xFF6888FD), + ), + child:Center( + child: Text('查询',style: TextStyle(fontSize: 12.sp,color: Colors.white),), + ), + ), + ) + ], + ), + ), + + + jobConditionFilter(context, + controller: tabController, + customTimeStr: customTimeStr, + customTime: tabController.index != 3 || + ((endDataTime == null || endDataTime == '') && (startDataTime == null || startDataTime == '')) + ? null + : PickerDateRange( + startDataTime == null || startDataTime == '' ? null : DateTime.parse(startDataTime!), + endDataTime == null || endDataTime == '' ? null : DateTime.parse(endDataTime!), + ), onTimeFilter: (String? startTime, String? endTime) { + EasyLoading.show(status: 'loading...'); + if (startTime == null && endTime == null) { + if (tabController.index == 3) { + tabController.animateTo(0); + } + startDataTime = ''; + endDataTime = ''; + customTimeStr = '自定义'; + } else { + startDataTime = startTime != null ? startTime : ''; + endDataTime = endTime != null ? endTime : ''; + } + page = 1; + setState(() {}); + getList(); + // _refreshController2.callRefresh(); + }, refreshTime: (value) { + if (value != null && value.startDate != null) { + customTimeStr = value.startDate?.toString().substring(0, 10) ?? ''; + setState(() {}); + if (value.endDate != null) { + if (!isPad() && value.startDate!.year == value.endDate!.year) { + customTimeStr = + value.startDate.toString().substring(5, 10) + '~${value.endDate.toString().substring(5, 10)}'; + setState(() {}); + } else { + customTimeStr = '$customTimeStr~${value.endDate?.toString().substring(0, 10)}'; + setState(() {}); + } + } + } + }), + Expanded( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 10.r), + child: EasyRefresh( + firstRefresh: false, + taskIndependence: true, + controller: refreshController, + header: MaterialHeader(), + footer: TaurusFooter(), + onRefresh: () async { + setState(() { + page = 1; + }); + getList(); + }, + onLoad: () async { + if (page < totalPages) { + setState(() { + page += 1; + }); + getList(); + } + }, + child: dataList.length > 0 + ? ListView.builder( + itemCount: dataList.length, + itemBuilder: (context, index) { + KnowledgePointsDetail item = dataList[index]; + return InkWell( + onTap: () { + /* RouterManager.router.navigateTo( + context, + RouterManager.quickCheckPersonalPath + + '?jobId=${item.jobName}&studentId=$studentId', + transition: getTransition(), + );*/ + }, + child: Container( + margin: EdgeInsets.symmetric(vertical: 5.r, horizontal: 14.r), + padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 10.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(10.r)), + color: Colors.white), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: Text( + item.jobName, + style: TextStyle(fontSize: 14.sp, color: Color(0xFF505050)), + )), + + Container( + width: 49.r, + height: 22.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(20.r)), + border: Border.all(width: 1.r, color: Color(0xFF6888FD)), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + '2次', + style: TextStyle(fontSize: 10.sp, color: Color(0xFF6888FD)), + ), + Image.asset('assets/images/right_icon_blue.png',width: 8.r,height: 8.r,), + ], + ), + ), + ], + ), + SizedBox(height: 10.r,), + progressBar(context, + title: '正确率:', + color: Color(0xFF90E0BE), + percent: item.correctRate / 100, + padingEdg: EdgeInsets.zero, + marginEdg: EdgeInsets.only(top: 8.h)), + ], + ), + ), + ); + }) + : MyEmptyWidget(), + ), + ), + ), + ], + ), + ); + } +} + +@swidget +Widget progressBar( + BuildContext context, { + double? fontSize, + double? lineHeight, + required String title, + required Color color, + required double percent, + required EdgeInsets padingEdg, + required EdgeInsets marginEdg, + }) { + var percentStr = '${doubleToStringAsFixed(percent * 100)}%'; + fontSize ??= 10.sp; + lineHeight ??= 8.h; + return Container( + margin: marginEdg, + padding: padingEdg, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (title == '总正确率:') quickText('确率', color: Colors.transparent, size: fontSize), + quickText(title, color: Color(0xFF8B8B8B), size: fontSize), + Expanded( + flex: 1, + child: Container( + child: Row( + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.r), + /* boxShadow: [ + BoxShadow( + color: color, + spreadRadius: 0.6, + blurRadius: 3, + offset: Offset(0, 0), + ), + ],*/ + ), + child: LinearPercentIndicator( + padding: EdgeInsets.zero, + animation: true, + lineHeight: lineHeight, + animationDuration: 2500, + percent: percent, + /* center: Text( + percentStr, + style: TextStyle(color: Colors.white, fontSize: 4.5.sp), + ),*/ + // linearStrokeCap: LinearStrokeCap.butt, + progressColor: color, + backgroundColor: Color(0xFFE8E8E8), + barRadius: Radius.circular(10.r), + // linearGradient: LinearGradient( + // tileMode: TileMode.mirror, + // stops: [0.0, 1.0], + // colors: [color.withOpacity(0.1), color], + // ), + ), + ), + ), + SizedBox(width: 4.w), + quickText(percentStr, size: fontSize, color: Color(0xFF464646)) + ], + ), + ), + ), + ], + ), + ); +} + +/// 已完成作业条件筛选栏 +@hwidget +Widget jobConditionFilter(BuildContext context, + {required TabController controller, + PickerDateRange? customTime, + required Function refreshTime, + required String customTimeStr, + required Function(String? startTime, String? endTime) onTimeFilter}) { + var customTimeState = PickerDateRange(null, null); + if (customTime != null) { + customTimeState = PickerDateRange(customTime!.startDate != null ? customTime!.startDate : null, + customTime!.endDate != null ? customTime!.endDate : null); + } + + DateTime getMonthStartDate() { + DateTime now = DateTime.now(); + return DateTime(now.year, now.month, 1); // 获取当前月份的第一天 + } + + DateTime getMonthEndDate() { + DateTime now = DateTime.now(); + int nextMonth = now.month + 1; + if (nextMonth > 12) { + nextMonth = 1; + now = now.add(Duration(days: 31 - now.day)); // 跨年了,所以加到当前月的最后一天 + } else { + now = now.add(Duration(days: DateTime(now.year, nextMonth, 0).day - now.day)); // 加到下个月的第一天的前一天,即本月最后一天 + } + return now; + } + + return Container( + // height: 39.h, + // padding: EdgeInsets.only(left: 4.w, right: 12.w), + decoration: BoxDecoration( + color: Color.fromRGBO(244, 244, 244, 1), + // border: Border(bottom: BorderSide(color: Color.fromRGBO(204, 204, 204, 1), width: 1)), + ), + child: Container( + alignment: Alignment.centerLeft, + decoration: BoxDecoration( + border: Border(bottom: BorderSide(width: 1.r,color: Color(0xFFCCCCCC))) + ), + child: TabBar( + controller: controller, + unselectedLabelStyle: TextStyle(fontSize: 12.sp, color: const Color.fromRGBO(102, 102, 102, 1)), + labelStyle: TextStyle( + fontSize: 12.sp, + fontWeight: FontWeight.bold, + color: Color.fromRGBO(116, 145, 253, 1), + ), + isScrollable: true, + labelColor: Color(0xFF6888FD), + unselectedLabelColor: Color(0xFF666666), + padding: EdgeInsets.symmetric(horizontal: 14.r), + // indicatorSize: TabBarIndicatorSize.label, // 设置指示器高度和标签一样高 + onTap: (int val) async { + switch (val) { + case 0: // 近一周 + onTimeFilter( + CommonUtils.getWeekStartDate().toString().substring(0, 10), + CommonUtils.getWeekEndDate().toString().substring(0, 10), + ); + break; + case 1: // 近一个月 + onTimeFilter( + getMonthStartDate().toString().substring(0, 10), + getMonthEndDate().toString().substring(0, 10), + ); + break; + default: // 自定义 + var dialogData = await showDialog( + context: context, + builder: (BuildContext context1) { + return Center( + child: Container( + color: Colors.white, + width: isPad() ? ScreenUtil().screenWidth / 2 : ScreenUtil().screenWidth / 1.3, + height: ScreenUtil().screenHeight / 2, + child: SfDateRangePicker( + showActionButtons: true, + confirmText: '确定', + cancelText: '取消', + onSubmit: (p0) { + print(p0); + Navigator.of(context1).pop(p0); + refreshTime(p0); + }, + onCancel: () { + Navigator.of(context1).pop(); + }, + selectionMode: DateRangePickerSelectionMode.range, + initialSelectedRange: customTimeState, + ), + ), + ); + }); + // startDate: 2024-03-04 18:47:00.117958, endDate: 2024-03-11 18:47:00.117986 + // if (dialogData != null && (dialogData.startDate != null || dialogData.endDate != null)) {} + onTimeFilter( + dialogData?.startDate?.toString().substring(0, 10), + dialogData?.endDate?.toString().substring(0, 10), + ); + customTimeState = dialogData!; + } + }, + tabs: [ + const Tab(text: '近一周'), + const Tab(text: '近一月'), + Tab(text: customTimeStr), + ], + ), + ), + ); +} diff --git a/marking_app/lib/pages/homework_correction/job_personal_detail.dart b/marking_app/lib/pages/homework_correction/job_personal_detail.dart index b40b7cf..9d3202b 100644 --- a/marking_app/lib/pages/homework_correction/job_personal_detail.dart +++ b/marking_app/lib/pages/homework_correction/job_personal_detail.dart @@ -60,6 +60,7 @@ class _JobPersonalDetailState extends State with CommonMixin, } void getList() async { + print(widget.studentId); RestClient _client = await getClient(); BaseStructureResult res = await _client.getStudentJobHistory(widget.studentId, !isJob, startDataTime, endDataTime, page, pageSize); diff --git a/marking_app/lib/pages/homework_correction/quick_check_personal.dart b/marking_app/lib/pages/homework_correction/quick_check_personal.dart index e53aef8..e883b0c 100644 --- a/marking_app/lib/pages/homework_correction/quick_check_personal.dart +++ b/marking_app/lib/pages/homework_correction/quick_check_personal.dart @@ -117,7 +117,7 @@ class _QuickCheckPersonalState extends State ), ), SizedBox(width: 10.r,), - /*Container( + Container( width: 93.r, height: 28.r, decoration: BoxDecoration( @@ -127,7 +127,7 @@ class _QuickCheckPersonalState extends State child: Center( child: Text('原稿笔迹',style: TextStyle(fontSize: 10.r,color: Color(0xFF4CC793)),), ), - ),*/ + ), ], ), ), diff --git a/marking_app/lib/routes/RouterManager.dart b/marking_app/lib/routes/RouterManager.dart index 21516c5..8a267bd 100644 --- a/marking_app/lib/routes/RouterManager.dart +++ b/marking_app/lib/routes/RouterManager.dart @@ -14,6 +14,8 @@ import 'package:flutter/material.dart'; import 'package:marking_app/common/model/enum/marking_list_type.dart'; import 'package:marking_app/pages/common/startUpPage.dart'; import 'package:marking_app/pages/homework_correction/do_papers_job_exam.dart'; +import 'package:marking_app/pages/homework_correction/job_knowledge_points.dart'; +import 'package:marking_app/pages/homework_correction/job_knowledge_points_detail.dart'; import 'package:marking_app/pages/homework_correction/job_personal_detail.dart'; import 'package:marking_app/pages/homework_correction/job_priority_review_set.dart'; import 'package:marking_app/pages/homework_correction/job_report.dart'; @@ -77,6 +79,8 @@ class RouterManager { static const String jobPersonalDetailPath = '/homework_correction/job_personal_detail'; static const String reportCardDialogPath = '/report_detail/widgets/report_card_dialog'; static const String reportHistoryPath = '/report_detail/report_history'; + static const String jobKnowledgePointsPath = '/homework_correction/job_knowledge_points'; + static const String jobKnowledgePointsDetailPath = '/homework_correction/job_knowledge_points_detail'; // TheMine @@ -363,6 +367,24 @@ class RouterManager { return ReportHistory(); }, ); + + // 知识点掌握 + static final _jobKnowledgePointsPathHandler = Handler( + handlerFunc: (BuildContext? context, Map> params) { + /* String studentName = params['studentName']![0]; + int studentId = int.parse(params['studentId']![0]);*/ + return JobKnowledgePoints(); + }, + ); + + // 知识点掌握详情 + static final _jobKnowledgePointsDetailPathHandler = Handler( + handlerFunc: (BuildContext? context, Map> params) { + String knowledgeName = params['knowledgeName']![0]; + int knowledgeId = int.parse(params['knowledgeId']![0]); + return JobKnowledgePointsDetail(knowledgeName:knowledgeName,knowledgeId:knowledgeId); + }, + ); // 开始阅卷页面 // static final _doMarkingPapers = Handler(handlerFunc: (BuildContext? context, Map> params) => MarkingPapers()); @@ -409,6 +431,8 @@ class RouterManager { router.define(jobPersonalDetailPath, handler: _jobPersonalDetailPathHandler, transitionType: TransitionType.material); router.define(reportCardDialogPath, handler: _reportCardDialogPathHandler, transitionType: TransitionType.material); router.define(reportHistoryPath, handler: _reportHistoryPathHandler, transitionType: TransitionType.material); + router.define(jobKnowledgePointsPath, handler: _jobKnowledgePointsPathHandler, transitionType: TransitionType.material); + router.define(jobKnowledgePointsDetailPath, handler: _jobKnowledgePointsDetailPathHandler, transitionType: TransitionType.material); // getTransition() diff --git a/marking_app/lib/utils/common_utils.dart b/marking_app/lib/utils/common_utils.dart index 19d129f..a9d31c4 100644 --- a/marking_app/lib/utils/common_utils.dart +++ b/marking_app/lib/utils/common_utils.dart @@ -45,4 +45,26 @@ class CommonUtils { } return hms; } + + static DateTime getWeekStartDate() { + DateTime now = DateTime.now(); + int dayOfWeek = now.weekday; // 获取今天是周几(1代表周一,7代表周日) + int diff = dayOfWeek - 1; // 计算今天距离周一的天数差 + if (diff < 0) { + diff += 7; // 如果是周日,则需要加上一周的天数 + } + return now.subtract(Duration(days: diff)); // 减去天数差,得到本周一的时间 + } + + static DateTime getWeekEndDate() { + DateTime now = DateTime.now(); + int dayOfWeek = now.weekday; // 获取今天是周几 + int diff = 7 - dayOfWeek; // 计算今天距离周日的天数差 + if (diff == 0) { + diff = 7; // 如果是周日,则加上一周的天数 + } + return now.add(Duration(days: diff)); // 加上天数差减一,得到本周日的时间 + } + + } From 7e3c6882e92bf3fbf247946b787600ea172f269b Mon Sep 17 00:00:00 2001 From: machuanyu <840649825@qq.com> Date: Thu, 11 Apr 2024 17:19:21 +0800 Subject: [PATCH 05/28] =?UTF-8?q?=E5=90=88=E5=B9=B6=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- marking_app/lib/routes/RouterManager.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/marking_app/lib/routes/RouterManager.dart b/marking_app/lib/routes/RouterManager.dart index ab530a2..a2f6186 100644 --- a/marking_app/lib/routes/RouterManager.dart +++ b/marking_app/lib/routes/RouterManager.dart @@ -14,6 +14,7 @@ import 'package:flutter/material.dart'; import 'package:marking_app/common/model/enum/marking_list_type.dart'; import 'package:marking_app/pages/common/startUpPage.dart'; import 'package:marking_app/pages/homework_correction/do_papers_job_exam.dart'; +import 'package:marking_app/pages/homework_correction/index.dart'; import 'package:marking_app/pages/homework_correction/job_knowledge_points.dart'; import 'package:marking_app/pages/homework_correction/job_knowledge_points_detail.dart'; import 'package:marking_app/pages/homework_correction/job_personal_detail.dart'; From 5cdf645f868d05d4d243cd16078cab3ffe163e4b Mon Sep 17 00:00:00 2001 From: machuanyu <840649825@qq.com> Date: Thu, 11 Apr 2024 17:24:00 +0800 Subject: [PATCH 06/28] -- --- .../lib/pages/homework_correction/job_home.dart | 4 ++-- marking_app/lib/utils/request/rest_client.dart | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/marking_app/lib/pages/homework_correction/job_home.dart b/marking_app/lib/pages/homework_correction/job_home.dart index 9916e0a..b7d94a0 100644 --- a/marking_app/lib/pages/homework_correction/job_home.dart +++ b/marking_app/lib/pages/homework_correction/job_home.dart @@ -39,7 +39,7 @@ class _JobHomeState extends State with CommonMixin, EventBusMixin, Auto EntranceModel( title: '知识点掌握', image: '', - navigationUrl: '', + navigationUrl: RouterManager.jobKnowledgePointsPath, ), EntranceModel( title: '答题轨迹', @@ -49,7 +49,7 @@ class _JobHomeState extends State with CommonMixin, EventBusMixin, Auto EntranceModel( title: '优先批阅设定', image: '', - navigationUrl: '', + navigationUrl: RouterManager.jobStudentGroupPath, ), EntranceModel( title: '批阅设置', diff --git a/marking_app/lib/utils/request/rest_client.dart b/marking_app/lib/utils/request/rest_client.dart index 8fc35b9..614d087 100644 --- a/marking_app/lib/utils/request/rest_client.dart +++ b/marking_app/lib/utils/request/rest_client.dart @@ -18,8 +18,9 @@ import 'package:marking_app/common/model/job/job_concerned_with_student_params.d import 'package:marking_app/common/model/job/job_data_report.dart'; import 'package:marking_app/common/model/job/job_do_marking_status_info.dart'; import 'package:marking_app/common/model/job/job_fav_student.dart'; -import 'package:marking_app/common/model/job/job_favorite_item_model.dart'; import 'package:marking_app/common/model/job/job_favorite_model.dart'; +import 'package:marking_app/common/model/job/job_knowledge_points.dart'; +import 'package:marking_app/common/model/job/job_knowledge_points_detail.dart'; import 'package:marking_app/common/model/job/job_level_set_params.dart'; import 'package:marking_app/common/model/job/job_note_taking_trajectory.dart'; import 'package:marking_app/common/model/job/job_page_tab.dart'; @@ -33,7 +34,6 @@ import 'package:marking_app/common/model/job/job_student_history.dart'; import 'package:marking_app/common/model/job/job_student_level.dart'; import 'package:marking_app/common/model/job/job_task_item.dart'; import 'package:marking_app/common/model/job/marking_text_question_job.dart'; -import 'package:marking_app/common/model/job/marking_text_question_job_params.dart'; import 'package:marking_app/common/model/job/marking_text_question_job_tab_params.dart'; import 'package:marking_app/common/model/job/review_again_list_params.dart'; import 'package:marking_app/common/model/job/upload_file_interface_config.dart'; @@ -357,5 +357,17 @@ abstract class RestClient { @the_retrofit.Query("PageSize") int pageSize, ); + // 作业 => 知识点掌握 + @the_retrofit.GET("/api/jobs/knowledge-report") + Future>> getKnowledgeReport( + /* @the_retrofit.Query("dateStart") String? dateStart, + @the_retrofit.Query("dateEnd") String? dateEnd,*/ + @the_retrofit.Query("knowledgeName") String? knowledgeName, + ); + // 作业 => 知识点掌握详情 + @the_retrofit.GET("/api/jobs/knowledge-detail-report") + Future>> getKnowledgeReportDetail( + @the_retrofit.Query("KnowledgeId") int knowledgeId, + ); } From 326a2fe99e9b435a03de419bc7289e310ae25b83 Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Thu, 11 Apr 2024 17:31:02 +0800 Subject: [PATCH 07/28] no message --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index c1a9ebb..eb137e1 100644 --- a/.gitignore +++ b/.gitignore @@ -215,3 +215,6 @@ marking_app/lib/common/model/event_bus/jobs/job_do_papers_submit_check_switch_bu marking_app/lib/common/model/event_bus/jobs/job_do_synchro_tab.g.dart marking_app/lib/pages/homework_correction/widget/top_count.g.dart marking_app/lib/common/model/event_bus/job_home_refresh_bus.g.dart +marking_app/lib/common/model/job/job_knowledge_points_detail.g.dart +marking_app/lib/common/model/job/job_knowledge_points.g.dart +marking_app/lib/pages/homework_correction/job_knowledge_points.g.dart From e22d5f26550c3007499f31bd59f3b2fde1f813d6 Mon Sep 17 00:00:00 2001 From: machuanyu <840649825@qq.com> Date: Fri, 12 Apr 2024 11:22:27 +0800 Subject: [PATCH 08/28] =?UTF-8?q?=E7=9F=A5=E8=AF=86=E7=82=B9=E8=AF=A6?= =?UTF-8?q?=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../job/job_knowledge_detail_student.dart | 29 + .../job/job_knowledge_detail_student.g.dart | 25 + .../lib/pages/homework_correction/index.dart | 17 - .../job_knowledge_points.dart | 5 +- .../job_knowledge_points_detail.dart | 650 +++++++++--------- .../lib/utils/request/rest_client.dart | 18 +- 6 files changed, 384 insertions(+), 360 deletions(-) create mode 100644 marking_app/lib/common/model/job/job_knowledge_detail_student.dart create mode 100644 marking_app/lib/common/model/job/job_knowledge_detail_student.g.dart diff --git a/marking_app/lib/common/model/job/job_knowledge_detail_student.dart b/marking_app/lib/common/model/job/job_knowledge_detail_student.dart new file mode 100644 index 0000000..43f34b2 --- /dev/null +++ b/marking_app/lib/common/model/job/job_knowledge_detail_student.dart @@ -0,0 +1,29 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'job_knowledge_detail_student.g.dart'; + + +@JsonSerializable() +class JobKnowledgeDetailStudent extends Object { + + @JsonKey(name: 'studentId') + int studentId; + + @JsonKey(name: 'studentName') + String studentName; + + @JsonKey(name: 'isAnswer') + bool isAnswer; + + @JsonKey(name: 'isCorrect') + bool isCorrect; + + JobKnowledgeDetailStudent(this.studentId,this.studentName,this.isAnswer,this.isCorrect,); + + factory JobKnowledgeDetailStudent.fromJson(Map srcJson) => _$JobKnowledgeDetailStudentFromJson(srcJson); + + Map toJson() => _$JobKnowledgeDetailStudentToJson(this); + +} + + diff --git a/marking_app/lib/common/model/job/job_knowledge_detail_student.g.dart b/marking_app/lib/common/model/job/job_knowledge_detail_student.g.dart new file mode 100644 index 0000000..9a570b7 --- /dev/null +++ b/marking_app/lib/common/model/job/job_knowledge_detail_student.g.dart @@ -0,0 +1,25 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'job_knowledge_detail_student.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +JobKnowledgeDetailStudent _$JobKnowledgeDetailStudentFromJson( + Map json) => + JobKnowledgeDetailStudent( + json['studentId'] as int, + json['studentName'] as String, + json['isAnswer'] as bool, + json['isCorrect'] as bool, + ); + +Map _$JobKnowledgeDetailStudentToJson( + JobKnowledgeDetailStudent instance) => + { + 'studentId': instance.studentId, + 'studentName': instance.studentName, + 'isAnswer': instance.isAnswer, + 'isCorrect': instance.isCorrect, + }; diff --git a/marking_app/lib/pages/homework_correction/index.dart b/marking_app/lib/pages/homework_correction/index.dart index 8bee856..b3314ad 100644 --- a/marking_app/lib/pages/homework_correction/index.dart +++ b/marking_app/lib/pages/homework_correction/index.dart @@ -274,23 +274,6 @@ class _HomeworkCorrectionState extends ConsumerState ), ), - /* Row( - children: [ - InkWell( - onTap: (){ - RouterManager.router.navigateTo( - context, - RouterManager.jobKnowledgePointsPath, - transition: getTransition(), - ); - }, - child: SizedBox( - height: 30.r, - child: Text('知识点掌握')), - ), - ], - ),*/ - if (_tabIndex == 1) $CompletedJobConditionFilter( controller: _tabController2, diff --git a/marking_app/lib/pages/homework_correction/job_knowledge_points.dart b/marking_app/lib/pages/homework_correction/job_knowledge_points.dart index dd410b2..d114935 100644 --- a/marking_app/lib/pages/homework_correction/job_knowledge_points.dart +++ b/marking_app/lib/pages/homework_correction/job_knowledge_points.dart @@ -67,7 +67,7 @@ class _JobKnowledgePointsState extends State with CommonMixi print('endDataTime=$endDataTime'); RestClient _client = await getClient(); BaseStructureResult> res = - await _client.getKnowledgeReport(textController.text); + await _client.getKnowledgeReport(startDataTime,endDataTime,textController.text); if (res.success) { setState(() { if (page == 1) { @@ -317,7 +317,6 @@ Widget progressBar( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - if (title == '总正确率:') quickText('确率', color: Colors.transparent, size: fontSize), quickText(title, color: Color(0xFF8B8B8B), size: fontSize), Expanded( flex: 1, @@ -360,7 +359,7 @@ Widget progressBar( ), ), SizedBox(width: 4.w), - quickText(percentStr, size: fontSize, color: Color(0xFF464646)) + quickText(percentStr, size: fontSize, color: Color(0xFF606060)) ], ), ), diff --git a/marking_app/lib/pages/homework_correction/job_knowledge_points_detail.dart b/marking_app/lib/pages/homework_correction/job_knowledge_points_detail.dart index f5be7a1..8506b57 100644 --- a/marking_app/lib/pages/homework_correction/job_knowledge_points_detail.dart +++ b/marking_app/lib/pages/homework_correction/job_knowledge_points_detail.dart @@ -6,6 +6,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:functional_widget_annotation/functional_widget_annotation.dart'; import 'package:marking_app/common/mixin/common.dart'; import 'package:marking_app/common/model/common/base_structure_result.dart'; +import 'package:marking_app/common/model/job/job_knowledge_detail_student.dart'; import 'package:marking_app/common/model/job/job_knowledge_points.dart'; import 'package:marking_app/common/model/job/job_knowledge_points_detail.dart'; import 'package:marking_app/common/model/job/job_student_history.dart'; @@ -17,41 +18,36 @@ import 'package:marking_app/utils/index.dart'; import 'package:marking_app/utils/my_text.dart'; import 'package:marking_app/utils/request/rest_client.dart'; import 'package:percent_indicator/percent_indicator.dart'; +import 'package:photo_view/photo_view.dart'; import 'package:syncfusion_flutter_datepicker/datepicker.dart'; - class JobKnowledgePointsDetail extends StatefulWidget { -final String knowledgeName; -final int knowledgeId; - const JobKnowledgePointsDetail({Key? key,required this.knowledgeName,required this.knowledgeId}) : super(key: key); + final String knowledgeName; + final int knowledgeId; + + const JobKnowledgePointsDetail( + {Key? key, required this.knowledgeName, required this.knowledgeId}) + : super(key: key); @override - _JobKnowledgePointsDetailState createState() => _JobKnowledgePointsDetailState(); + _JobKnowledgePointsDetailState createState() => + _JobKnowledgePointsDetailState(); } -class _JobKnowledgePointsDetailState extends State with CommonMixin, TickerProviderStateMixin { +class _JobKnowledgePointsDetailState extends State + with CommonMixin, TickerProviderStateMixin { @override - int page = 1; - int pageSize = 10; - int totalPages = 0; - late TabController tabController; - String startDataTime = CommonUtils.getWeekStartDate().toString().substring(0, 10); - String endDataTime = CommonUtils.getWeekEndDate().toString().substring(0, 10); - String customTimeStr = '自定义'; List dataList = []; + List studentList = []; late final EasyRefreshController refreshController; + String paperImg = ''; - //文本输入框控制器 - late final TextEditingController textController; - int studentId = 0; + int studentId = 0; @override void initState() { super.initState(); - textController = TextEditingController(); - refreshController = EasyRefreshController(); - tabController = TabController(length: 3, vsync: this); EasyLoading.show(status: 'loading...'); getList(); } @@ -59,36 +55,135 @@ class _JobKnowledgePointsDetailState extends State wit @override void dispose() { super.dispose(); - tabController.dispose(); - textController.dispose(); } void getList() async { RestClient _client = await getClient(); BaseStructureResult> res = - await _client.getKnowledgeReportDetail(widget.knowledgeId); + await _client.getKnowledgeReportDetail(widget.knowledgeId); if (res.success) { setState(() { - if (page == 1) { - dataList = res.data!; - } else { - dataList = [...dataList, ...res.data!]; - } - - // totalPages = res.data!.pagedList.totalPages; + dataList = res.data!; }); } EasyLoading.dismiss(); } + showStudent(questionid, title) async { + await getStudents(questionid); + + showModalBottomSheet( + context: context, + elevation: 10, + backgroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20.r), + topRight: Radius.circular(20.r), + ), + ), + builder: (BuildContext context) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 2.w), + child: Column( + children: [ + Container( + margin: EdgeInsets.only(top: 14.h), + child: quickText( + title, + size: 18.sp, + fontWeight: FontWeight.bold, + color: Color.fromRGBO(60, 60, 60, 1), + ), + ), + Expanded( + child: ListView( + padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 4.w), + children: [ + Wrap( + spacing: 6.r, // 主轴(水平)方向间距 + runSpacing: 4.r, // 纵轴(垂直)方向间距 + alignment: WrapAlignment.spaceAround, //沿主轴方向居中 + children: studentList.map((e) { + return Container( + padding: EdgeInsets.symmetric( + vertical: 4.r, horizontal: 8.r), + decoration: BoxDecoration( + color: e.isAnswer + ? Color(0xFF4CC793) + : Color(0xFFE2E2E2), + borderRadius: BorderRadius.circular(4.r), + ), + child: quickText(e.studentName, + color: + e.isAnswer ? Colors.white : Color(0xFF505E6E), + size: 10.sp), + ); + }).toList(), + ), + ], + ), + ) + ], + ), + ); + }, + ); + EasyLoading.dismiss(); + } + + showImg(int sectionId, String questionNo) async { + await getImg(sectionId, questionNo); + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + insetPadding: EdgeInsets.symmetric(vertical: 55.r,horizontal: 45.r), + contentPadding: EdgeInsets.all(0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(15.r))), + content: Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, + child: Image.network(paperImg), + ), + ); + }, + ); + EasyLoading.dismiss(); + } + + getStudents(questionid) async { + RestClient _client = await getClient(); + BaseStructureResult> res = + await _client.getKnowledgeStudent(questionid); + if (res.success) { + studentList = res.data!; + } else { + studentList = []; + } + } + + getImg(int sectionId, String questionNo) async { + RestClient _client = await getClient(); + BaseStructureResult res = + await _client.getKnowledgeImg(sectionId, questionNo); + if (res.success) { + paperImg = res.data!; + } else { + paperImg = ''; + } + } + @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Color.fromRGBO(245, 245, 245, 1), appBar: AppBar( backgroundColor: Colors.white, - title: Text(widget.knowledgeName, style: TextStyle(fontSize: 14.sp, color: Color(0xFF333333))), + title: Text(widget.knowledgeName, + style: TextStyle(fontSize: 14.sp, color: Color(0xFF333333))), centerTitle: true, leading: IconButton( icon: Icon(Icons.arrow_back_ios, color: Colors.black), @@ -99,197 +194,177 @@ class _JobKnowledgePointsDetailState extends State wit ], elevation: 0, ), - body: Column( - children: [ - Container( - margin: EdgeInsets.all(15.r), - height: 30.r, - child: Row( - children: [ - Expanded( - child: Container( - padding: EdgeInsets.only(left: 10.r,right: 10.r), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6.r), - border: Border.all(width: 1.r,color: Color(0xFFDDDDDD)), - color: Colors.white, - ), - child: TextField( - controller: textController, - textInputAction: TextInputAction.next, - style: TextStyle( - color: const Color.fromRGBO(80, 87, 103, 1), - fontSize: 10.sp, - ), - decoration: InputDecoration( - hintText: "请输入知识点名称", - hintStyle: TextStyle(fontSize: 10.sp, color: const Color.fromRGBO(153, 153, 153, 1)), - labelStyle: TextStyle(fontSize: 10.sp, color: const Color.fromRGBO(148, 163, 182, 1)), - border: InputBorder.none, - ), - ), - ), - ), - SizedBox(width: 10.r,), - InkWell( - onTap: (){ - page = 1; - setState(() {}); - getList(); - }, - child: Container( - width: 50.r, - height: 30.r, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4.r), - color: Color(0xFF6888FD), - ), - child:Center( - child: Text('查询',style: TextStyle(fontSize: 12.sp,color: Colors.white),), - ), - ), - ) - ], - ), - ), - - - jobConditionFilter(context, - controller: tabController, - customTimeStr: customTimeStr, - customTime: tabController.index != 3 || - ((endDataTime == null || endDataTime == '') && (startDataTime == null || startDataTime == '')) - ? null - : PickerDateRange( - startDataTime == null || startDataTime == '' ? null : DateTime.parse(startDataTime!), - endDataTime == null || endDataTime == '' ? null : DateTime.parse(endDataTime!), - ), onTimeFilter: (String? startTime, String? endTime) { - EasyLoading.show(status: 'loading...'); - if (startTime == null && endTime == null) { - if (tabController.index == 3) { - tabController.animateTo(0); - } - startDataTime = ''; - endDataTime = ''; - customTimeStr = '自定义'; - } else { - startDataTime = startTime != null ? startTime : ''; - endDataTime = endTime != null ? endTime : ''; - } - page = 1; - setState(() {}); - getList(); - // _refreshController2.callRefresh(); - }, refreshTime: (value) { - if (value != null && value.startDate != null) { - customTimeStr = value.startDate?.toString().substring(0, 10) ?? ''; - setState(() {}); - if (value.endDate != null) { - if (!isPad() && value.startDate!.year == value.endDate!.year) { - customTimeStr = - value.startDate.toString().substring(5, 10) + '~${value.endDate.toString().substring(5, 10)}'; - setState(() {}); - } else { - customTimeStr = '$customTimeStr~${value.endDate?.toString().substring(0, 10)}'; - setState(() {}); - } - } - } - }), - Expanded( - child: Padding( - padding: EdgeInsets.symmetric(vertical: 10.r), - child: EasyRefresh( - firstRefresh: false, - taskIndependence: true, - controller: refreshController, - header: MaterialHeader(), - footer: TaurusFooter(), - onRefresh: () async { - setState(() { - page = 1; - }); - getList(); - }, - onLoad: () async { - if (page < totalPages) { - setState(() { - page += 1; - }); - getList(); - } - }, - child: dataList.length > 0 - ? ListView.builder( - itemCount: dataList.length, - itemBuilder: (context, index) { - KnowledgePointsDetail item = dataList[index]; - return InkWell( - onTap: () { + body: Padding( + padding: EdgeInsets.symmetric(vertical: 10.r), + child: EasyRefresh( + firstRefresh: false, + taskIndependence: true, + controller: refreshController, + header: MaterialHeader(), + footer: TaurusFooter(), + onRefresh: () async { + getList(); + }, + onLoad: () async { + // getList(); + }, + child: dataList.length > 0 + ? ListView.builder( + itemCount: dataList.length, + itemBuilder: (context, index) { + KnowledgePointsDetail item = dataList[index]; + return InkWell( + onTap: () { /* RouterManager.router.navigateTo( - context, - RouterManager.quickCheckPersonalPath + - '?jobId=${item.jobName}&studentId=$studentId', - transition: getTransition(), - );*/ - }, - child: Container( - margin: EdgeInsets.symmetric(vertical: 5.r, horizontal: 14.r), - padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 10.r), - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(10.r)), - color: Colors.white), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Expanded( - child: Text( - item.jobName, - style: TextStyle(fontSize: 14.sp, color: Color(0xFF505050)), - )), - - Container( + context, + RouterManager.quickCheckPersonalPath + + '?jobId=${item.jobName}&studentId=$studentId', + transition: getTransition(), + );*/ + }, + child: Container( + margin: EdgeInsets.symmetric( + vertical: 5.r, horizontal: 14.r), + padding: EdgeInsets.symmetric( + vertical: 14.r, horizontal: 10.r), + decoration: BoxDecoration( + borderRadius: + BorderRadius.all(Radius.circular(10.r)), + color: Colors.white), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + item.publishTime.substring(0, 10), + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF505050)), + ), + SizedBox( + width: 10.r, + ), + Expanded( + child: Text( + item.jobName, + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF505050)), + )), + InkWell( + onTap: () { + EasyLoading.show(status: 'loading...'); + showImg(item.sectionId, item.questionNo); + }, + child: Container( width: 49.r, height: 22.r, decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(20.r)), - border: Border.all(width: 1.r, color: Color(0xFF6888FD)), + borderRadius: BorderRadius.all( + Radius.circular(20.r)), + border: Border.all( + width: 1.r, color: Color(0xFF8B8B8B)), ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - '2次', - style: TextStyle(fontSize: 10.sp, color: Color(0xFF6888FD)), + child: Center( + child: Text( + '${item.questionNo}题', + style: TextStyle( + fontSize: 10.sp, + color: Color(0xFF8B8B8B)), + ), + ), + ), + ), + ], + ), + SizedBox( + height: 10.r, + ), + Container( + margin: EdgeInsets.only(top: 8.h), + padding: EdgeInsets.zero, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + InkWell( + onTap: () { + EasyLoading.show(status: 'loading...'); + showStudent( + item.questionId, item.jobName); + }, + child: Container( + margin: EdgeInsets.only(right: 6.r), + width: 56.r, + height: 20.r, + decoration: BoxDecoration( + color: Color(0xFFD4FFED), + borderRadius: + BorderRadius.circular(20.r), ), - Image.asset('assets/images/right_icon_blue.png',width: 8.r,height: 8.r,), - ], + child: Center( + child: quickText('正确率 >', + color: Color(0xFF4CC793), + size: 10.sp))), + ), + Expanded( + flex: 1, + child: Container( + child: Row( + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + borderRadius: + BorderRadius.circular(10.r), + ), + child: LinearPercentIndicator( + padding: EdgeInsets.zero, + animation: true, + lineHeight: 8.h, + animationDuration: 2500, + percent: item.correctRate / 100, + progressColor: + Color(0xFF90E0BE), + backgroundColor: + Color(0xFFE8E8E8), + barRadius: + Radius.circular(10.r), + ), + ), + ), + SizedBox(width: 4.w), + quickText( + '${doubleToStringAsFixed(item.correctRate / 100 * 100)}%', + size: 10.sp, + color: Color(0xFF606060)) + ], + ), ), ), ], ), - SizedBox(height: 10.r,), - progressBar(context, - title: '正确率:', - color: Color(0xFF90E0BE), - percent: item.correctRate / 100, - padingEdg: EdgeInsets.zero, - marginEdg: EdgeInsets.only(top: 8.h)), - ], - ), + ), + /* progressBar(context, + title: '正确率 >', + color: Color(0xFF90E0BE), + percent: item.correctRate / 100, + padingEdg: EdgeInsets.zero, + marginEdg: EdgeInsets.only(top: 8.h), + studentCall:showStudent(item.questionId,item.jobName), + ),*/ + ], ), - ); - }) - : MyEmptyWidget(), - ), - ), - ), - ], + ), + ); + }) + : MyEmptyWidget(), + ), ), ); } @@ -297,15 +372,16 @@ class _JobKnowledgePointsDetailState extends State wit @swidget Widget progressBar( - BuildContext context, { - double? fontSize, - double? lineHeight, - required String title, - required Color color, - required double percent, - required EdgeInsets padingEdg, - required EdgeInsets marginEdg, - }) { + BuildContext context, { + double? fontSize, + double? lineHeight, + required String title, + required Color color, + required double percent, + required EdgeInsets padingEdg, + required EdgeInsets marginEdg, + required Future studentCall, +}) { var percentStr = '${doubleToStringAsFixed(percent * 100)}%'; fontSize ??= 10.sp; lineHeight ??= 8.h; @@ -316,8 +392,22 @@ Widget progressBar( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - if (title == '总正确率:') quickText('确率', color: Colors.transparent, size: fontSize), - quickText(title, color: Color(0xFF8B8B8B), size: fontSize), + InkWell( + onTap: () { + studentCall; + }, + child: Container( + margin: EdgeInsets.only(right: 6.r), + width: 56.r, + height: 20.r, + decoration: BoxDecoration( + color: Color(0xFFD4FFED), + borderRadius: BorderRadius.circular(20.r), + ), + child: Center( + child: quickText(title, + color: Color(0xFF4CC793), size: fontSize))), + ), Expanded( flex: 1, child: Container( @@ -359,7 +449,7 @@ Widget progressBar( ), ), SizedBox(width: 4.w), - quickText(percentStr, size: fontSize, color: Color(0xFF464646)) + quickText(percentStr, size: fontSize, color: Color(0xFF606060)) ], ), ), @@ -368,119 +458,3 @@ Widget progressBar( ), ); } - -/// 已完成作业条件筛选栏 -@hwidget -Widget jobConditionFilter(BuildContext context, - {required TabController controller, - PickerDateRange? customTime, - required Function refreshTime, - required String customTimeStr, - required Function(String? startTime, String? endTime) onTimeFilter}) { - var customTimeState = PickerDateRange(null, null); - if (customTime != null) { - customTimeState = PickerDateRange(customTime!.startDate != null ? customTime!.startDate : null, - customTime!.endDate != null ? customTime!.endDate : null); - } - - DateTime getMonthStartDate() { - DateTime now = DateTime.now(); - return DateTime(now.year, now.month, 1); // 获取当前月份的第一天 - } - - DateTime getMonthEndDate() { - DateTime now = DateTime.now(); - int nextMonth = now.month + 1; - if (nextMonth > 12) { - nextMonth = 1; - now = now.add(Duration(days: 31 - now.day)); // 跨年了,所以加到当前月的最后一天 - } else { - now = now.add(Duration(days: DateTime(now.year, nextMonth, 0).day - now.day)); // 加到下个月的第一天的前一天,即本月最后一天 - } - return now; - } - - return Container( - // height: 39.h, - // padding: EdgeInsets.only(left: 4.w, right: 12.w), - decoration: BoxDecoration( - color: Color.fromRGBO(244, 244, 244, 1), - // border: Border(bottom: BorderSide(color: Color.fromRGBO(204, 204, 204, 1), width: 1)), - ), - child: Container( - alignment: Alignment.centerLeft, - decoration: BoxDecoration( - border: Border(bottom: BorderSide(width: 1.r,color: Color(0xFFCCCCCC))) - ), - child: TabBar( - controller: controller, - unselectedLabelStyle: TextStyle(fontSize: 12.sp, color: const Color.fromRGBO(102, 102, 102, 1)), - labelStyle: TextStyle( - fontSize: 12.sp, - fontWeight: FontWeight.bold, - color: Color.fromRGBO(116, 145, 253, 1), - ), - isScrollable: true, - labelColor: Color(0xFF6888FD), - unselectedLabelColor: Color(0xFF666666), - padding: EdgeInsets.symmetric(horizontal: 14.r), - // indicatorSize: TabBarIndicatorSize.label, // 设置指示器高度和标签一样高 - onTap: (int val) async { - switch (val) { - case 0: // 近一周 - onTimeFilter( - CommonUtils.getWeekStartDate().toString().substring(0, 10), - CommonUtils.getWeekEndDate().toString().substring(0, 10), - ); - break; - case 1: // 近一个月 - onTimeFilter( - getMonthStartDate().toString().substring(0, 10), - getMonthEndDate().toString().substring(0, 10), - ); - break; - default: // 自定义 - var dialogData = await showDialog( - context: context, - builder: (BuildContext context1) { - return Center( - child: Container( - color: Colors.white, - width: isPad() ? ScreenUtil().screenWidth / 2 : ScreenUtil().screenWidth / 1.3, - height: ScreenUtil().screenHeight / 2, - child: SfDateRangePicker( - showActionButtons: true, - confirmText: '确定', - cancelText: '取消', - onSubmit: (p0) { - print(p0); - Navigator.of(context1).pop(p0); - refreshTime(p0); - }, - onCancel: () { - Navigator.of(context1).pop(); - }, - selectionMode: DateRangePickerSelectionMode.range, - initialSelectedRange: customTimeState, - ), - ), - ); - }); - // startDate: 2024-03-04 18:47:00.117958, endDate: 2024-03-11 18:47:00.117986 - // if (dialogData != null && (dialogData.startDate != null || dialogData.endDate != null)) {} - onTimeFilter( - dialogData?.startDate?.toString().substring(0, 10), - dialogData?.endDate?.toString().substring(0, 10), - ); - customTimeState = dialogData!; - } - }, - tabs: [ - const Tab(text: '近一周'), - const Tab(text: '近一月'), - Tab(text: customTimeStr), - ], - ), - ), - ); -} diff --git a/marking_app/lib/utils/request/rest_client.dart b/marking_app/lib/utils/request/rest_client.dart index 614d087..6d8789a 100644 --- a/marking_app/lib/utils/request/rest_client.dart +++ b/marking_app/lib/utils/request/rest_client.dart @@ -19,6 +19,7 @@ import 'package:marking_app/common/model/job/job_data_report.dart'; import 'package:marking_app/common/model/job/job_do_marking_status_info.dart'; import 'package:marking_app/common/model/job/job_fav_student.dart'; import 'package:marking_app/common/model/job/job_favorite_model.dart'; +import 'package:marking_app/common/model/job/job_knowledge_detail_student.dart'; import 'package:marking_app/common/model/job/job_knowledge_points.dart'; import 'package:marking_app/common/model/job/job_knowledge_points_detail.dart'; import 'package:marking_app/common/model/job/job_level_set_params.dart'; @@ -360,8 +361,8 @@ abstract class RestClient { // 作业 => 知识点掌握 @the_retrofit.GET("/api/jobs/knowledge-report") Future>> getKnowledgeReport( - /* @the_retrofit.Query("dateStart") String? dateStart, - @the_retrofit.Query("dateEnd") String? dateEnd,*/ + @the_retrofit.Query("dateStart") String? dateStart, + @the_retrofit.Query("dateEnd") String? dateEnd, @the_retrofit.Query("knowledgeName") String? knowledgeName, ); @@ -370,4 +371,17 @@ abstract class RestClient { Future>> getKnowledgeReportDetail( @the_retrofit.Query("KnowledgeId") int knowledgeId, ); + + // 作业 => 知识点掌握详情人员名单 + @the_retrofit.GET("/api/jobs/knowledge-question-detail/{questionid}") + Future>> getKnowledgeStudent( + @the_retrofit.Path("questionid") int questionid, + ); + + // 作业 => 知识点掌握详情原卷图 + @the_retrofit.GET("/api/jobs/question-paper-img/{sectionid}/{questionno}") + Future> getKnowledgeImg( + @the_retrofit.Path("sectionid") int questionid, + @the_retrofit.Path("questionno") String questionno, + ); } From 42d2e4ab3944b971c63dfb4f296ef66f57b891d7 Mon Sep 17 00:00:00 2001 From: machuanyu <840649825@qq.com> Date: Mon, 15 Apr 2024 13:47:26 +0800 Subject: [PATCH 09/28] =?UTF-8?q?=E5=8E=86=E5=8F=B2=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/homework_correction/job_home.dart | 15 ++++-- .../job_knowledge_points_detail.dart | 2 +- .../job_priority_review_set.dart | 48 ++++++++++++++++--- .../job_student_group.dart | 5 +- marking_app/lib/routes/RouterManager.dart | 6 ++- 5 files changed, 61 insertions(+), 15 deletions(-) diff --git a/marking_app/lib/pages/homework_correction/job_home.dart b/marking_app/lib/pages/homework_correction/job_home.dart index b7d94a0..f82a76c 100644 --- a/marking_app/lib/pages/homework_correction/job_home.dart +++ b/marking_app/lib/pages/homework_correction/job_home.dart @@ -34,7 +34,9 @@ class _JobHomeState extends State with CommonMixin, EventBusMixin, Auto EntranceModel( title: '学生历史作业', image: '', - navigationUrl: '', + navigationUrl: RouterManager.jobStudentGroupPath, + page:'history', + ), EntranceModel( title: '知识点掌握', @@ -50,6 +52,7 @@ class _JobHomeState extends State with CommonMixin, EventBusMixin, Auto title: '优先批阅设定', image: '', navigationUrl: RouterManager.jobStudentGroupPath, + page:'set', ), EntranceModel( title: '批阅设置', @@ -143,7 +146,12 @@ class _JobHomeState extends State with CommonMixin, EventBusMixin, Auto return InkWell( onTap: () => easyThrottle('GO_TO_JOB_HOME_NAVIGATION', () { - RouterManager.router.navigateTo(context, e.navigationUrl, transition: getTransition()); + if(e.page != ''){ + RouterManager.router.navigateTo(context, '${e.navigationUrl}?page=${e.page}', transition: getTransition()); + }else{ + RouterManager.router.navigateTo(context, e.navigationUrl, transition: getTransition()); + } + }), child: badges.Badge( showBadge: isJob && data > 0, @@ -188,5 +196,6 @@ class EntranceModel extends Object { String title; String image; String navigationUrl; - EntranceModel({required this.title, required this.image, required this.navigationUrl}); + String? page; + EntranceModel({required this.title, required this.image, required this.navigationUrl,this.page = ''}); } diff --git a/marking_app/lib/pages/homework_correction/job_knowledge_points_detail.dart b/marking_app/lib/pages/homework_correction/job_knowledge_points_detail.dart index 8506b57..9b71be4 100644 --- a/marking_app/lib/pages/homework_correction/job_knowledge_points_detail.dart +++ b/marking_app/lib/pages/homework_correction/job_knowledge_points_detail.dart @@ -145,7 +145,7 @@ class _JobKnowledgePointsDetailState extends State borderRadius: BorderRadius.all(Radius.circular(15.r))), content: Container( width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height, + // height: MediaQuery.of(context).size.height, child: Image.network(paperImg), ), ); diff --git a/marking_app/lib/pages/homework_correction/job_priority_review_set.dart b/marking_app/lib/pages/homework_correction/job_priority_review_set.dart index ceb876a..ce7d6ff 100644 --- a/marking_app/lib/pages/homework_correction/job_priority_review_set.dart +++ b/marking_app/lib/pages/homework_correction/job_priority_review_set.dart @@ -16,8 +16,9 @@ import 'package:marking_app/utils/request/rest_client.dart'; class JobPriorityReviewSet extends StatefulWidget { final String groupId; final String title; + final String? page; - const JobPriorityReviewSet({Key? key, required this.groupId,required this.title}) + const JobPriorityReviewSet({Key? key, required this.groupId,required this.title,this.page = ''}) : super(key: key); @override @@ -208,7 +209,16 @@ class _JobPriorityReviewSetState extends State color: Color(0xFF6888FD)), )), item.readLevel == 1 - ? InkWell( + ? + widget.page == 'history'?Container( + height: 20.r, + width: 70.r, + decoration: BoxDecoration( + color: Color(0xFF6888FD), + borderRadius: BorderRadius.all(Radius.circular(20.r)) + ), + child: Center(child: Text('历史作业',style: TextStyle(fontSize: 10.r,color: Colors.white),)), + ):InkWell( onTap: () { setState(() { isClicking = true; @@ -218,7 +228,7 @@ class _JobPriorityReviewSetState extends State EasyLoading.show( status: 'loading...'); }, - child: Container( + child:Container( height: 20.r, width: 70.r, decoration: BoxDecoration( @@ -246,7 +256,15 @@ class _JobPriorityReviewSetState extends State ), ), ) - : InkWell( + : widget.page == 'history'?Container( + height: 20.r, + width: 70.r, + decoration: BoxDecoration( + color: Color(0xFF6888FD), + borderRadius: BorderRadius.all(Radius.circular(20.r)) + ), + child: Center(child: Text('历史作业',style: TextStyle(fontSize: 10.r,color: Colors.white),)), + ):InkWell( onTap: () { setState(() { isClicking = true; @@ -256,7 +274,7 @@ class _JobPriorityReviewSetState extends State EasyLoading.show( status: 'loading...'); }, - child: Container( + child: Container( height: 20.r, width: 70.r, decoration: BoxDecoration( @@ -347,7 +365,15 @@ class _JobPriorityReviewSetState extends State color: Color(0xFF6888FD)), )), item.readLevel == 1 - ? InkWell( + ? widget.page == 'history'?Container( + height: 24.r, + width: 82.r, + decoration: BoxDecoration( + color: Color(0xFF6888FD), + borderRadius: BorderRadius.all(Radius.circular(20.r)) + ), + child: Center(child: Text('历史作业',style: TextStyle(fontSize: 10.r,color: Colors.white),)), + ):InkWell( onTap: () { setState(() { isClicking = true; @@ -385,7 +411,15 @@ class _JobPriorityReviewSetState extends State ), ), ) - : InkWell( + : widget.page == 'history'?Container( + height: 24.r, + width: 82.r, + decoration: BoxDecoration( + color: Color(0xFF6888FD), + borderRadius: BorderRadius.all(Radius.circular(20.r)) + ), + child: Center(child: Text('历史作业',style: TextStyle(fontSize: 10.r,color: Colors.white),)), + ):InkWell( onTap: () { setJobReadLevel( item.studentGroupDetailId, 1); diff --git a/marking_app/lib/pages/homework_correction/job_student_group.dart b/marking_app/lib/pages/homework_correction/job_student_group.dart index c5856cb..1690ce6 100644 --- a/marking_app/lib/pages/homework_correction/job_student_group.dart +++ b/marking_app/lib/pages/homework_correction/job_student_group.dart @@ -16,7 +16,8 @@ import 'package:marking_app/utils/index.dart'; import 'package:marking_app/utils/request/rest_client.dart'; class JobStudentGroup extends StatefulWidget { - const JobStudentGroup({Key? key}) : super(key: key); + final String page; + const JobStudentGroup({Key? key,required this.page}) : super(key: key); @override State createState() => _JobStudentGroupState(); @@ -59,7 +60,7 @@ class _JobStudentGroupState extends State with CommonMixin { } void goNextPage(id,title){ - RouterManager.router.navigateTo(context, '${RouterManager.jobPriorityReviewSetPath}?&groupId=$id&title=${Uri.encodeComponent(title)}',transition: getTransition()); + RouterManager.router.navigateTo(context, '${RouterManager.jobPriorityReviewSetPath}?&groupId=$id&title=${Uri.encodeComponent(title)}&page=${widget.page}',transition: getTransition()); } @override diff --git a/marking_app/lib/routes/RouterManager.dart b/marking_app/lib/routes/RouterManager.dart index a2f6186..2ae466d 100644 --- a/marking_app/lib/routes/RouterManager.dart +++ b/marking_app/lib/routes/RouterManager.dart @@ -317,14 +317,16 @@ class RouterManager { handlerFunc: (BuildContext? context, Map> params) { String groupId = params['groupId']![0]; String title = params['title']![0]; - return JobPriorityReviewSet(groupId: groupId,title:title); + String? page = params['page']?[0]; + return JobPriorityReviewSet(groupId: groupId,title:title,page:page); }, ); //学生分组 static final _jobStudentGroupPageHandler = Handler( handlerFunc: (BuildContext? context, Map> params) { - return JobStudentGroup(); + String page = params['page']![0]; + return JobStudentGroup(page:page); }, ); //作业收藏页面 From 6e2010a7ccd361b50784626a80b326a3a2c974eb Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Mon, 15 Apr 2024 14:15:48 +0800 Subject: [PATCH 10/28] no message --- .gitignore | 3 +++ .../job/job_knowledge_detail_student.g.dart | 25 ------------------- 2 files changed, 3 insertions(+), 25 deletions(-) delete mode 100644 marking_app/lib/common/model/job/job_knowledge_detail_student.g.dart diff --git a/.gitignore b/.gitignore index eb137e1..0cb371a 100644 --- a/.gitignore +++ b/.gitignore @@ -218,3 +218,6 @@ marking_app/lib/common/model/event_bus/job_home_refresh_bus.g.dart marking_app/lib/common/model/job/job_knowledge_points_detail.g.dart marking_app/lib/common/model/job/job_knowledge_points.g.dart marking_app/lib/pages/homework_correction/job_knowledge_points.g.dart +marking_app/lib/pages/homework_correction/job_knowledge_points_detail.g.dart +marking_app/lib/common/model/job/job_knowledge_detail_student.g.dart +marking_app/lib/common/model/job/job_knowledge_detail_student.g.dart diff --git a/marking_app/lib/common/model/job/job_knowledge_detail_student.g.dart b/marking_app/lib/common/model/job/job_knowledge_detail_student.g.dart deleted file mode 100644 index 9a570b7..0000000 --- a/marking_app/lib/common/model/job/job_knowledge_detail_student.g.dart +++ /dev/null @@ -1,25 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'job_knowledge_detail_student.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -JobKnowledgeDetailStudent _$JobKnowledgeDetailStudentFromJson( - Map json) => - JobKnowledgeDetailStudent( - json['studentId'] as int, - json['studentName'] as String, - json['isAnswer'] as bool, - json['isCorrect'] as bool, - ); - -Map _$JobKnowledgeDetailStudentToJson( - JobKnowledgeDetailStudent instance) => - { - 'studentId': instance.studentId, - 'studentName': instance.studentName, - 'isAnswer': instance.isAnswer, - 'isCorrect': instance.isCorrect, - }; From 4e812bc5c0040ae966601e725d6341b99bcb679f Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Mon, 15 Apr 2024 15:41:13 +0800 Subject: [PATCH 11/28] no message --- .gitignore | 1 + .../assets/images/2.0x/job_home_top_bgm.png | Bin 0 -> 234527 bytes .../assets/images/3.0x/job_home_top_bgm.png | Bin 0 -> 477908 bytes .../assets/images/4.0x/job_home_top_bgm.png | Bin 0 -> 741015 bytes .../assets/images/job_home_top_bgm.png | Bin 0 -> 71014 bytes .../pages/homework_correction/job_home.dart | 302 +++++++++++++++--- 6 files changed, 250 insertions(+), 53 deletions(-) create mode 100644 marking_app/assets/images/2.0x/job_home_top_bgm.png create mode 100644 marking_app/assets/images/3.0x/job_home_top_bgm.png create mode 100644 marking_app/assets/images/4.0x/job_home_top_bgm.png create mode 100644 marking_app/assets/images/job_home_top_bgm.png diff --git a/.gitignore b/.gitignore index 0cb371a..8d99daf 100644 --- a/.gitignore +++ b/.gitignore @@ -221,3 +221,4 @@ marking_app/lib/pages/homework_correction/job_knowledge_points.g.dart marking_app/lib/pages/homework_correction/job_knowledge_points_detail.g.dart marking_app/lib/common/model/job/job_knowledge_detail_student.g.dart marking_app/lib/common/model/job/job_knowledge_detail_student.g.dart +marking_app/lib/pages/homework_correction/job_home.g.dart diff --git a/marking_app/assets/images/2.0x/job_home_top_bgm.png b/marking_app/assets/images/2.0x/job_home_top_bgm.png new file mode 100644 index 0000000000000000000000000000000000000000..69830419b43a84010e71c3fd006a52b7d8d639e9 GIT binary patch literal 234527 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 z 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 + +

2. 信息的存储

+2.1 信息存储的方式和期限 +
    +
  • 我们会通过安全的方式存储您的信息,包括本地存储(例如利用APP进行数据缓存)、数据库和服务器日志。
  • +
  • 一般情况下,我们只会在为实现服务目的所必需的时间内或法律法规规定的条件下存储您的个人信息。
  • +
+ +2.2 信息存储的地域 +
    +
  • 我们会按照法律法规规定,将境内收集的用户个人信息存储于中国境内。
  • +
  • 目前我们不会跨境传输或存储您的个人信息。将来如需跨境传输或存储的,我们会向您告知信息出境的目的、接收方、安全保证措施和安全风险,并征得您的同意。
  • +
+ +2.3 产品或服务停止运营时的通知 +
    +
  • 当我们的产品或服务发生停止运营的情况时,我们将以推送通知、公告等形式通知您,并在合理期限内删除您的个人信息或进行匿名化处理,法律法规另有规定的除外。
  • +
+ +

3. 信息安全

+

+我们使用各种安全技术和程序,以防信息的丢失、不当使用、未经授权阅览或披露。例如,在某些服务中,我们将利用加密技术(例如SSL)来保护您提供的个人信息。但请您理解,由于技术的限制以及可能存在的各种恶意手段,在互联网行业,即便竭尽所能加强安全措施,也不可能始终保证信息百分之百的安全。您需要了解,您接入我们的服务所用的系统和通讯网络,有可能因我们可控范围外的因素而出现问题。 +

+ +

4. 我们如何使用信息

+

我们可能将在向您提供服务的过程之中所收集的信息用作下列用途:

+
    +
  • 向您提供服务;
  • +
  • 在我们提供服务时,用于身份验证、客户服务、安全防范、诈骗监测、存档和备份用途,确保我们向您提供的产品和服务的安全性;
  • +
  • 帮助我们设计新服务,改善我们现有服务;
  • +
  • 使我们更加了解您如何接入和使用我们的服务,从而针对性地回应您的个性化需求,例如语言设定、位置设定、个性化的帮助服务和指示,或对您和其他用户作出其他方面的回应;
  • +
  • 向您提供与您更加相关的广告以替代普遍投放的广告;
  • +
  • 评估我们服务中的广告和其他促销及推广活动的效果,并加以改善;
  • +
  • 软件认证或管理软件升级;
  • +
  • 让您参与有关我们产品和服务的调查。
  • +
+ +

5. 信息共享

+

+目前,我们不会主动共享或转让您的个人信息至第三方,如存在其他共享或转让您的个人信息或您需要我们将您的个人信息共享或转让至第三方情形时,我们会直接或确认第三方征得您对上述行为的明示同意。 +

+

+为了投放广告,评估、优化广告投放效果等目的,我们需要向广告主及其代理商等第三方合作伙伴共享您的部分数据,要求其严格遵守我们关于数据隐私保护的措施与要求,包括但不限于根据数据保护协议、承诺书及相关数据处理政策进行处理,避免识别出个人身份,保障隐私安全。 +

+

+我们不会向合作伙伴分享可用于识别您个人身份的信息(例如您的姓名或电子邮件地址),除非您明确授权。 +

+

+我们不会对外公开披露所收集的个人信息,如必须公开披露时,我们会向您告知此次公开披露的目的、披露信息的类型及可能涉及的敏感信息,并征得您的明示同意。 +

+

+随着我们业务的持续发展,我们有可能进行合并、收购、资产转让等交易,我们将告知您相关情形,按照法律法规及不低于本《隐私政策》所要求的标准继续保护或要求新的控制者继续保护您的个人信息。 +

+

+另外,根据相关法律法规及国家标准,以下情形中,我们可能会共享、转让、公开披露个人信息无需事先征得您的授权同意: +

+
    +
  • 与国家安全、国防安全直接相关的;
  • +
  • 与公共安全、公共卫生、重大公共利益直接相关的;
  • +
  • 犯罪侦查、起诉、审判和判决执行等直接相关的;
  • +
  • 出于维护个人信息主体或其他个人的生命、财产等重大合法权益但又很难得到本人同意的;
  • +
  • 个人信息主体自行向社会公众公开个人信息的;
  • +
  • 从合法公开披露的信息中收集个人信息的,如合法的新闻报道、政府信息公开等渠道。
  • +
+ +

6. 您的权利

+

+在您使用我们的服务期间,我们可能会视产品具体情况为您提供相应的操作设置,以便您可以查询、删除、更正或撤回您的相关个人信息,您可参考相应的具体指引进行操作。此外,我们还设置了投诉举报渠道,您的意见将会得到及时的处理。如果您无法通过上述途径和方式行使您的个人信息主体权利,您可以通过本《隐私政策》中提供的联系方式提出您的请求,我们会按照法律法规的规定予以反馈。 +

+

当您决定不再使用我们的产品或服务时,可以申请注销账户。注销账户后,除法律法规另有规定外,我们将删除或匿名化处理您的个人信息。

+ +

7. 变更

+

+我们可能适时修订本《隐私政策》的条款。当变更发生时,我们会在版本更新时向您提示新的《隐私政策》,并向您说明生效日期。请您仔细阅读变更后的《隐私政策》内容,若您继续使用我们的服务,即表示您同意我们按照更新后的《隐私政策》处理您的个人信息。 +

+ +

8. 未成年人保护

+

+我们鼓励父母或监护人指导未满十八岁的未成年人使用我们的服务。我们建议未成年人鼓励他们的父母或监护人阅读本《隐私政策》,并建议未成年人在提交的个人信息之前寻求父母或监护人的同意和指导。 +

+ +''', ), AGREEMENT_KEY.USER_AGREEMENT: AgreementClass( title: '用户协议', - richText: - '''

用户在使用技术开发方(即,以下统称“技术开发方”)提供的各项服务之前,应仔细阅读本《用户协议》(以下简称“本协议”)。用户一旦登录或使用技术开发方的服务,即视为用户已了解并明示同意本协议各项内容,本协议立即在用户与本技术开发方之间产生法律效力。用户登录、使用本产品服务的全部活动将受到本协议的约束并承担相应的责任和义务。如用户不同意本协议任何内容的,请用户立即停止使用技术开发方所提供的全部服务。 根据《中华人民共和国网络安全法》、《电信和互联网用户个人信息保护规定》及相关法律法规的规定,同时依据技术开发方与其合作伙伴之间的相关协议,用户必须已明示授权技术开发方合作伙伴(以下简称“合作伙伴”)、在此明示授权并委托技术开发方及其关联公司通过官方或相关实名认证平台、信用信息平台(包括但不限于:征信机构、银行信用信息平台、网络借贷平台、消费金融平台、第三方支付平台、公积金平台、投资理财平台等)及其它相关平台查询、验证、存储用户的个人信用信息,并输出给合作伙伴对用户的个人信用进行评估与参考使用。用户理解并同意,具体的授权查询、验证、存储及输出的内容以合作伙伴要求查询、验证、存储、输出以及技术开发方及其关联公司实际查询、验证、存储、输出的信息为准。技术开发方及其关联公司会在授权范围内对相关个人信息予以处理(包括但不限于为保护用户个人信息而加密处理、掩码处理等一切为实现相关协议目的而进行的所有必要处理)并仅提供给合作伙伴使用,但用户与合作伙伴之间因授权的有效性、授权内容、授权范围、授权期限等发生的争议纠纷与技术开发方无关。如用户对合作伙伴的上述授权事项有任何异议或争议的,应立即停止使用技术开发方所提供的全部服务。用户使用本服务的,即表明用户已明示对合作伙伴、技术开发方及其关联公司授权查询、验证、处理、存储、在约定范围内使用其个人信息,并对授权的效力、查询验证的内容、查询验证平台、处理方式、使用范围等相关事项无任何事实或法律上的异议或争议。 鉴于用户须授权合作伙伴并由该合作伙伴告知本服务后方能进入、登录并使用本服务,用户登录或使用本服务时起即视为用户与技术开发方的合作伙伴之间已存在合法的、充分的、必要的、不可撤销的授权,且用户已清楚知晓其授权提供相关信息可能对其造成的相关不利影响,如负面的信用评价等。为保护用户个人信息,技术开发方会采取合理措施对用户信息进行严格保密,同时督促并要求该特定合作伙伴进行严格保密。未经用户授权,技术开发方及其关联公司不会将用户信息提供给任何其他方。

一、协议主体

本协议是用户与技术开发方关于用户使用本服务所订立的协议。

二、关于本服务


    1. 本服务内容是指技术开发方通过本应用程序向其合作伙伴及用户提供的相关服务(简称“本服务”)。


    1. 对用户使用的本服务,技术开发方会不断丰富用户使用本服务的终端、形式等。


    1. 许可的范围:
      -(1)技术开发方授予用户一项个人的、不可转让及非排他性的许可,以使用本应用程序。
      -(2)本条及本协议其他条款未明示授权的其他一切知识产权权利仍由技术开发方保留。技术开发方如果未行使前述任何权利,并不构成对该权利的放弃。

三、账号登录

为使用本应用程序用户可能需要输入个人信息进行登录与使用。 用户清楚知晓,其向技术开发方提供的账户仅限本人使用,否则,用户可能会对用户或他人造成侵权。用户承诺并同意,使用同一设备、同一身份证号或账号使用本协议项下服务的,均视为用户本人的行为。用户应妥善保管自身设备、身份证件及账号密码信息,审慎交由他人使用或使用他人设备、身份证件或账户信息,如用户违反本约定给用户或他人造成损失的,技术开发方不应也不会承担任何法律责任。用户若因此给技术开发方造成损失的,应承担技术开发方所遭受的全部损失。

四、应用程序的使用

如果用户从非技术开发方合作伙伴的应用程序或非技术开发方合作伙伴处获取本应用程序或与本应用程序名称相同的安装程序,技术开发方无法保证该应用程序能够正常使用,并对因此给用户造成的损失不予负责。

五、应用程序的更新

  1. 为了增进用户体验、完善服务内容,技术开发方将不断努力为用户时时提供应用程序更新(这些更新可能会采取应用程序替换、修改、功能强化、版本升级等形式)。

  2. 为了改善用户体验,并保证服务的安全性和功能的一致性,技术开发方有权不经向用户特别通知而对应用程序进行更新,或者对应用程序的部分功能效果进行改变或限制。

六、用户个人信息保护


    1. 保护用户个人信息是技术开发方的一项基本原则,技术开发方将会采取合理的措施保护用户的个人信息。除法律法规规定及用户授权的情形外,未经用户许可技术开发方不会向任何第三方公开、透露用户个人信息。


    1. 用户在登录账号或使用本服务的过程中,可能需要填写一些必要的信息。若用户填写的信息不真实或不完整,则可能无法正常使用本服务。


    1. 一般情况下,用户可随时浏览、修改自己提交的信息,但出于安全性和身份识别的考虑,用户可能无法修改注册时提供的初始注册信息及其他验证信息。


    1. 技术开发方将运用各种安全技术和程序建立完善的管理制度来保护用户的个人信息,以免遭受未经授权的访问、使用或披露。

七、授权事项及行为规范


    1. 授权事项
      -(1)用户充分理解并同意:用户在使用本服务时,可能需要使用用户终端设备的相关权限、接口及相关设备信息等才能实现相应的功能。
      -(2)用户可以选择不向技术开发方提供用户的某些信息,但因此可能会导致相关服务功能无法实现。
      -(3)为实现本协议目的为合作伙伴及用户提供更加优质、安全的服务,用户同意并明示授权技术开发方及其关联公司对用户的相关个人信息进行查询、验证、存储、处理并在约定范围内使用(提供给用户已授权的合作伙伴对用户进行信用评估及参考使用)。技术开发方及其关联公司对用户的个人信息进行严格保密。本协议项下的授权为不可撤销的授权。
      -(4)用户知晓并明示授权同意技术开发方及其关联公司依据相关法律法规的规定,受合作伙伴委托向第三方征信机构或数据机构等合法查询、验证、审核用户信息,上述信息包括但不限于个人基本信息、特征信息(包括但不限于用户的法院失信信息、网络失信信息、是否为羊毛党信息、是否曾使用通讯小号及可疑设备信息等)、关联信息(即用户的身份证信息、手机号、手机设备及银行卡之间的关联关系,以判断用户信息是否有异常,该关联关系不涉及具体的个人敏感信息)、借贷交易信息、网络投资理财信息、公积金信息、公用事业信息、央行征信报告、个人网络数据信息等合作伙伴需要验证或参考使用的相关用户信息。技术开发方具体查询、验证及审核的信息最终以合作伙伴需要验证、需要参考使用及实际验证与使用的信息为准。技术开发方对所获取的信息,仅在用户与合作伙伴之间有关个人信用信息评估等合作伙伴业务相关工作中使用。技术开发方及其关联公司将对所获取的信息向该合作伙伴进行提供,除此之外,未经用户授权,技术开发方及其关联公司不得也不会向其他机构或个人泄露、披露或提供用户的信息


    1. 用户禁止行为除非法律允许或技术开发方书面许可,用户不得从事下列行为:
      -(1)删除本应用程序及其副本上关于著作权的信息。
      -(2)对本应用程序进行反向工程、反向汇编、反向编译,或者以其他方式尝试发现本应用程序的源代码。
      -(3)对技术开发方拥有知识产权的内容进行使用、出租、出借、复制、修改、链接、转载、汇编、发表、出版等。
      -(4)通过修改或伪造应用程序运行中的指令、数据,增加、删减、变动应用程序的功能或运行效果,或者将用于上述用途的应用程序、方法进行运营或向公众传播,无论这些行为是否为商业目的。
      -(5)自行、授权他人或利用第三方应用程序对本应用程序及其组件、模块、数据等进行干扰。
      -(6)其他未经技术开发方明示授权的行为。

  1. 对自己行为负责用户充分了解并同意,用户必须为自己对合作伙伴的授权(包括但不限于授权方式、授权内容及授权期限等)以及其账户下的相关行为负责。技术开发方会督促合作伙伴获取用户的授权后方能对相关信息进行查询、验证或使用并要求合作伙伴对用户的信息进行严格保密,但用户应对使用本服务时接触到的内容自行加以判断,如对授权相关事项及信息安全有任何异议或争议的,应立即停止使用本服务。技术开发方无法且不会对用户与合作伙伴之间的任何争议或纠纷而承担责任,用户未按约定要求立即停止使用本服务的,技术开发方对非因技术开发方的原因而产生的任何风险或损失将不承担任何责任。

八、知识产权声明


    1. 技术开发方是本应用程序的知识产权权利人。本应用程序的著作权、商标权、专利权、商业秘密等知识产权,以及与本应用程序相关的所有信息内容(包括但不限于文字、图片、音频、视频、图表、界面设计、版面框架、有关数据或电子文档等)均受中华人民共和国法律法规和相应的国际条约保护,技术开发方依法享有上述相关知识产权,但相关权利人依照法律规定应享有的权利除外。


    1. 未经技术开发方或相关权利人书面同意,用户不得为任何商业或非商业目的自行或许可任何第三方实施、利用、转让上述知识产权。

九、终端安全责任


    1. 用户理解并同意,本应用程序或本服务同大多数互联网应用程序、服务一样,可能会受多种因素影响(包括但不限于用户原因、网络服务质量、社会环境等);也可能会受各种安全问题的侵扰(包括但不限于他人非法利用用户资料,进行现实中的骚扰;用户下载安装的其他应用程序或访问的其他网站中可能含有病毒、木马程序或其他恶意程序,威胁用户终端的信息和数据的安全,继而影响本应用程序、本服务的正常使用等)。因此,用户应加强信息安全及个人信息的保护意识,注意密码保护,以免遭受损失。出现上述情况时技术开发方将努力在第一时间与相关方配合,及时进行修复,但是由此给用户造成的损失技术开发方在法律允许的范围内免责。


    1. 用户不得制作、发布、使用、传播用于窃取技术开发方账号及他人个人信息、财产的恶意程序。


    1. 维护应用程序安全与正常使用是技术开发方和用户的共同责任,技术开发方将按照行业标准合理审慎地采取必要技术措施保护用户的终端信息和数据安全。


    1. 在法律允许的范围内,技术开发方对以下情形导致的服务中断或受阻不承担责任:
      -(1)受到计算机病毒、木马或其他恶意程序、黑客攻击的破坏。
      -(2)用户或技术开发方的电脑软件、系统、硬件和通信线路出现故障。
      -(3)用户操作不当。
      -(4)用户通过非技术开发方授权的方式使用本服务。
      -(5)其他技术开发方无法控制或合理预见的情形。

十、不可抗力及合理免责

“不可抗力”是指在本协议签订后发生的、受影响一方无法预见、无法避免并无法克服的客观情况。此等事件包括但不限于水灾、火灾、旱灾、台风、地震及其它自然灾害、罢工、骚动、暴乱及战争以及政府部门的作为或不作为、法律法规或政策调整、数据来源变更(包括但不限于其服务内容及形式的变更)、国内数据渠道瘫痪、黑客攻击、计算机病毒侵入、新型病毒爆发、因电信运营商问题导致网络中断服务器不可访问、停电、系统故障、传输线路、通信故障等技术开发方无法控制的因素。因受不可抗力影响而不能履行或不能完全履行本协议的不视为违约,不应承担相应违约责任 。

十一、其他


    1. 用户使用本应用程序或本服务即视为用户已阅读并同意受本协议的约束。技术开发方有权在必要时修改本协议条款。用户可以在本应用程序、本服务的最新版本中查阅相关协议条款。本协议条款变更后,如果用户继续登录、使用本应用程序、本服务,即视为用户已接受修改后的协议。如果用户不接受修改后的协议,应当停止使用本应用程序。


    1. 本协议的成立、生效、履行、解释及纠纷解决,适用中华人民共和国大陆地区法律(不包括冲突法)。


    1. 若用户和技术开发方之间发生任何纠纷或争议,首先应友好协商解决;协商不成的,用户同意将纠纷或争议提交被告方所在地人民法院管辖。


    1. 本协议所有条款的标题仅为阅读方便,本身并无实际涵义,不能作为本协议涵义解释的依据。5. 本协议条款无论因何种原因部分无效或不可执行,其余条款仍有效,对双方具有约束力。




''', + richText: ''' + + + + + Document + + +

用户协议

+

重庆智学力人工智能科技有限公司(以下简称“我们”)依据本协议为用户(以下简称“你”)提供学而有道阅卷服务。本协议对你和我们均具有法律约束力。

+

一、本服务的功能

+

你可以使用本服务网络阅卷。

+

二、责任范围及限制

+

你使用本服务得到的结果仅供参考,实际情况以官方为准。

+

三、隐私保护

+

我们重视对你隐私的保护,你的个人隐私信息将根据《隐私政策》受到保护与规范,详情请参阅《隐私政策》。

+

四、其他条款

+

4.1 本协议所有条款的标题仅为阅读方便,本身并无实际涵义,不能作为本协议涵义解释的依据。

+

4.2 本协议条款无论因何种原因部分无效或不可执行,其余条款仍有效,对双方具有约束力。

+ + ''', ) }; diff --git a/marking_app/lib/utils/fast_data.dart b/marking_app/lib/utils/fast_data.dart index 93bb949..80f427e 100644 --- a/marking_app/lib/utils/fast_data.dart +++ b/marking_app/lib/utils/fast_data.dart @@ -41,6 +41,7 @@ class FastData { static const String _INPUT_KEYBOARD_GUIDE_PAGE_WORK = "APP:MARKING:GUIDE_PAGE:WORK"; // 系统协议确认 static const String _SYS_PROTOCOL = "APP:SYS:PROTOCOL"; + static const String _SYS_PROTOCOL_SHOW = "APP:SYS:PROTOCOL_SHOW"; static SharedPreferences? _prefs; @@ -286,4 +287,19 @@ class FastData { SharedPreferences thePrefs = await getSharedInstance(); thePrefs.remove(_SYS_PROTOCOL); } + + Future setSysProtocolShow(bool val) async { + SharedPreferences thePrefs = await getSharedInstance(); + return await thePrefs.setBool(_SYS_PROTOCOL_SHOW, val); + } + + Future getSysProtocolShow([SharedPreferences? thePrefs]) async { + if (thePrefs == null) thePrefs = await getSharedInstance(); + return thePrefs.getBool(_SYS_PROTOCOL_SHOW); + } + + void cleanSysProtocolShow() async { + SharedPreferences thePrefs = await getSharedInstance(); + thePrefs.remove(_SYS_PROTOCOL_SHOW); + } } diff --git a/marking_app/lib/utils/sys_protocol.dart b/marking_app/lib/utils/sys_protocol.dart index 50891c3..f1c00c2 100644 --- a/marking_app/lib/utils/sys_protocol.dart +++ b/marking_app/lib/utils/sys_protocol.dart @@ -74,6 +74,7 @@ class Protocol extends Dialog { ], ), ), + SizedBox(height: 10.h), Row( children: [ Expanded( @@ -122,17 +123,25 @@ class Protocol extends Dialog { } /// 系统协议 -void sysProtocol(BuildContext context) async { +Future sysProtocol(BuildContext context) async { bool? _sysProtocol = await FastData.getInstance().getSysProtocol(); if (_sysProtocol == null || !_sysProtocol) { print('进来这里....'); - - showDialog( - context: context, - barrierDismissible: false, - builder: (ctx) { - return Protocol(ctx); - }, - ); + bool? _sysProtocolShow = await FastData.getInstance().getSysProtocolShow(); + if (_sysProtocolShow != true) { + try { + await FastData.getInstance().setSysProtocolShow(true); + return showDialog( + context: context, + barrierDismissible: false, + // useRootNavigator: false, + builder: (ctx) => Protocol(ctx), + ); + } catch (e) { + FastData.getInstance().cleanSysProtocol(); + } finally { + FastData.getInstance().cleanSysProtocolShow(); + } + } } } From a759583ca0e808c4d9afacfd829c8b46abe0c134 Mon Sep 17 00:00:00 2001 From: machuanyu <840649825@qq.com> Date: Wed, 17 Apr 2024 17:13:24 +0800 Subject: [PATCH 19/28] =?UTF-8?q?=E7=AD=94=E9=A2=98=E8=BD=A8=E8=BF=B9?= =?UTF-8?q?=E6=8C=89=E4=BD=9C=E4=B8=9A=E8=AF=A6=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../answer_trajectory.dart | 2 +- .../answer_trajectory_job_detail.dart | 279 ++++++++++++++++++ .../widget/answer_trajectory_job.dart | 215 +++++++------- marking_app/lib/routes/RouterManager.dart | 13 +- 4 files changed, 406 insertions(+), 103 deletions(-) create mode 100644 marking_app/lib/pages/homework_correction/answer_trajectory_job_detail.dart diff --git a/marking_app/lib/pages/homework_correction/answer_trajectory.dart b/marking_app/lib/pages/homework_correction/answer_trajectory.dart index 4f3f0e1..cd25e60 100644 --- a/marking_app/lib/pages/homework_correction/answer_trajectory.dart +++ b/marking_app/lib/pages/homework_correction/answer_trajectory.dart @@ -127,7 +127,7 @@ class _AnswerTrajectoryState extends State backgroundColor: Colors.white, title: Text( '答题轨迹', - style: TextStyle(fontSize: 16.sp, color: Color(0xFF333333)), + style: TextStyle(fontSize: 14.sp, color: Color(0xFF333333)), ), centerTitle: true, leading: IconButton( diff --git a/marking_app/lib/pages/homework_correction/answer_trajectory_job_detail.dart b/marking_app/lib/pages/homework_correction/answer_trajectory_job_detail.dart new file mode 100644 index 0000000..967160c --- /dev/null +++ b/marking_app/lib/pages/homework_correction/answer_trajectory_job_detail.dart @@ -0,0 +1,279 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:marking_app/common/mixin/common.dart'; +import 'package:marking_app/common/model/common/base_structure_result.dart'; +import 'package:marking_app/common/model/job/job_concerned_with_student.dart'; +import 'package:marking_app/common/model/job/job_concerned_with_student_params.dart'; +import 'package:marking_app/common/model/job/job_task_item.dart'; +import 'package:marking_app/components/ReturnToHomepage.dart'; +import 'package:marking_app/routes/RouterManager.dart'; +import 'package:marking_app/utils/easy_refresh/MyEmptyWidget.dart'; +import 'package:marking_app/utils/index.dart'; +import 'package:marking_app/utils/request/rest_client.dart'; + +class AnswerTrajectoryJobDetail extends StatefulWidget { + final int jobId; + final String jobName; + final String genderName; + + const AnswerTrajectoryJobDetail( + {Key? key, + required this.jobId, + required this.jobName, + required this.genderName}) + : super(key: key); + + @override + State createState() => + _AnswerTrajectoryJobDetailState(); +} + +class _AnswerTrajectoryJobDetailState extends State + with CommonMixin { + List markList = []; + late MarkingTasks currentClass; + List students = []; + late final EasyRefreshController refreshController; + + @override + void initState() { + super.initState(); + refreshController = EasyRefreshController(); + EasyLoading.show(status: 'loading...'); + getData(); + } + + void getData() async { + RestClient _client = await getClient(); + BaseStructureResult> res = + await _client.getJobListParticipateInClass(widget.jobId); + if (res.success) { + setState(() { + markList = res.data!; + if (markList.length > 0) { + currentClass = markList[0]; + getStudentList(); + } + }); + } + } + + void getStudentList() async { + RestClient _client = await getClient(); + BaseStructureResult> res = + await _client.getJobWithStudents(JobConcernedWithStudentParams([currentClass.id])); + if (res.success) { + setState(() { + students = res.data!; + }); + } + refreshController.finishRefresh(); + EasyLoading.dismiss(); + } + + @override + void dispose() { + super.dispose(); + refreshController.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Color(0xFFF5F5F5), + appBar: AppBar( + centerTitle: true, + backgroundColor: Colors.white, + title: Text( + widget.jobName, + style: TextStyle(fontSize: 14.sp, color: Color(0xFF333333)), + overflow: TextOverflow.ellipsis, + ), + leading: IconButton( + icon: Icon(Icons.arrow_back_ios, color: Colors.black), + onPressed: () => Navigator.of(context).pop(), + ), + actions: [ + ReturnToHomepage(), + ], + ), + body: Column( + children: [ + SizedBox( + height: 10.r, + ), + if (markList.length > 0) + Padding( + padding: EdgeInsets.symmetric(horizontal: 14.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: List.generate(markList.length, (index) { + MarkingTasks item = markList[index]; + return InkWell( + onTap: (){ + if(currentClass.id != item.id){ + EasyLoading.show(status: 'loading...'); + setState(() { + currentClass = item; + }); + getStudentList(); + } + + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: 5.r, horizontal: 10.r), + margin: EdgeInsets.only( + right: index < markList.length ? 8.r : 0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(4.r), + ), + child: Center( + child: Text( + '${widget.genderName}${item.className}', + style: TextStyle( + fontSize: 10.sp, + color: currentClass.id == item.id + ? Color(0xFF6888FD) + : Color(0xFF686868)), + ), + ), + ), + ); + })), + ), + ], + ), + ), + SizedBox( + height: 10.r, + ), + Container( + height: 1.r, + color: Color(0xFFCCCCCC), + ), + students.length>0? Expanded( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 14.r), + child: EasyRefresh( + firstRefresh: true, + taskIndependence: true, + controller: refreshController, + header: MaterialHeader(), + footer: TaurusFooter(), + onRefresh: () async { + getStudentList(); + }, + child: students.length > 0 + ? isPad() + ? GridView( + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + mainAxisSpacing: 10.r, + crossAxisSpacing: 10.r, + childAspectRatio: 556 / 112, + ), + children: List.generate(students.length, (index) { + var item = students[index]; + return InkWell( + onTap: (){ + RouterManager.router.navigateTo(context, + '${RouterManager.jobPersonalDetailPath}?studentId=${item.studentId}&studentName=${Uri.encodeComponent(item.studentName)}'); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10.r), + decoration: BoxDecoration( + borderRadius: + BorderRadius.all(Radius.circular(10.r)), + color: Colors.white, + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + item.studentName, + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF6888FD)), + )), + + Container( + height: 20.r, + width: 70.r, + decoration: BoxDecoration( + border: Border.all(width: 1.r,color: Color(0xFFFFA41E)), + borderRadius: BorderRadius.all(Radius.circular(20.r)), + + ), + child: Center(child: Text('详情',style: TextStyle(fontSize: 10.r,color: Color(0xFFFFA41E))), + )), + ], + ), + ), + ); + }), + ) + : ListView.builder( + itemBuilder: (context, index) { + var item = students[index]; + return InkWell( + onTap: (){ + RouterManager.router.navigateTo(context, + '${RouterManager.jobPersonalDetailPath}?studentId=${item.studentId}&studentName=${Uri.encodeComponent(item.studentName)}'); + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: 20.r, horizontal: 15.r), + margin: EdgeInsets.only(bottom: 15.r), + decoration: BoxDecoration( + borderRadius: + BorderRadius.all(Radius.circular(10.r)), + color: Colors.white, + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + item.studentName, + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF6888FD)), + )), + Container( + height: 24.r, + width: 72.r, + decoration: BoxDecoration( + border: Border.all(width: 1.r,color: Color(0xFFFFA41E)), + borderRadius: BorderRadius.all(Radius.circular(20.r)), + + ), + child: Center(child: Text('详情',style: TextStyle(fontSize: 10.r,color: Color(0xFFFFA41E))), + )), + ], + ), + ), + ); + }, + itemCount: students.length, + ) + : MyEmptyWidget(), + ), + ), + ):MyEmptyWidget(), + ], + ), + ); + } +} diff --git a/marking_app/lib/pages/homework_correction/widget/answer_trajectory_job.dart b/marking_app/lib/pages/homework_correction/widget/answer_trajectory_job.dart index 7d8bd80..afc5cd9 100644 --- a/marking_app/lib/pages/homework_correction/widget/answer_trajectory_job.dart +++ b/marking_app/lib/pages/homework_correction/widget/answer_trajectory_job.dart @@ -5,6 +5,8 @@ import 'package:marking_app/utils/easy_refresh/MyEmptyWidget.dart'; import 'package:marking_app/utils/index.dart'; import 'package:marking_app/utils/my_text.dart'; +import '../../../routes/RouterManager.dart'; + class AnswerTrajectoryJob extends StatelessWidget { final List jobList; @@ -25,110 +27,117 @@ class AnswerTrajectoryJob extends StatelessWidget { ), children: List.generate(jobList.length, (index) { JobTaskItem item = jobList[index]; - return Container( - padding: EdgeInsets.only(top: 10.h), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6.r), - color: Colors.white, - boxShadow: [ - BoxShadow( - color: const Color.fromRGBO(210, 216, 241, 1), - offset: Offset.zero, //阴影y轴偏移量 - blurRadius: 5.8, //阴影模糊程度 - spreadRadius: 0, //阴影扩散程度 - ) - ], - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - // 顶部任务名称 - Padding( - padding: EdgeInsets.symmetric(horizontal: 6.w), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 32.w, - height: 18.h, - alignment: Alignment.center, - padding: EdgeInsets.only(left: 2.w), - decoration: BoxDecoration( - color: const Color.fromRGBO(104, 136, 253, 1), - borderRadius: BorderRadius.only( - topLeft: Radius.circular(14.r), - topRight: Radius.circular(3.r), - bottomLeft: Radius.circular(4.r), - bottomRight: Radius.circular(4.r), - ), - ), - margin: EdgeInsets.only(right: 4.w), - child: quickText(item.markingTypeEnum.name, - color: Colors.white, size: 10.sp), - ), - Expanded( - child: quickText(item.title, - size: 12.sp, - color: Color.fromRGBO(70, 70, 70, 1), - maxLines: 2), - ), - SizedBox( - width: 5.r, - ), - Container( - padding: EdgeInsets.symmetric( - vertical: 1.r, horizontal: 5.r), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4.r), - border: Border.all( - width: 1.r, color: Color(0xFF4CC793)), - ), - child: Center( - child: Text( - item.subjectName, - style: TextStyle( - fontSize: 8.r, - color: Color(0xFF4CC793)), - ), - ), - ) - ], - ), - ), - - Container( - padding: EdgeInsets.symmetric(vertical: 6.h), - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(6.r), - bottomRight: Radius.circular(6.r)), - color: Colors.white, - boxShadow: [ - BoxShadow( - color: const Color.fromRGBO(0, 0, 0, 0.15), - offset: Offset(0, -0.0001), //阴影y轴偏移量 - blurRadius: 4, //阴影模糊程度 - spreadRadius: 0, //阴影扩散程度 - ) - ], - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, + return InkWell( + onTap: (){ + RouterManager.router.navigateTo(context, + '${RouterManager.answerTrajectoryJobDetailPath}?&jobId=${item.id}&jobName=${Uri.encodeComponent(item.title)}&genderName=${Uri.encodeComponent(item.genderName)}', + transition: getTransition()); + }, + child: Container( + padding: EdgeInsets.only(top: 10.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6.r), + color: Colors.white, + boxShadow: [ + BoxShadow( + color: const Color.fromRGBO(210, 216, 241, 1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 5.8, //阴影模糊程度 + spreadRadius: 0, //阴影扩散程度 + ) + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + // 顶部任务名称 + Padding( + padding: EdgeInsets.symmetric(horizontal: 6.w), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( + width: 32.w, + height: 18.h, alignment: Alignment.center, - child: quickText('详情', - color: Color(0xFFFFA115), size: 12.sp), + padding: EdgeInsets.only(left: 2.w), + decoration: BoxDecoration( + color: const Color.fromRGBO(104, 136, 253, 1), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(14.r), + topRight: Radius.circular(3.r), + bottomLeft: Radius.circular(4.r), + bottomRight: Radius.circular(4.r), + ), + ), + margin: EdgeInsets.only(right: 4.w), + child: quickText(item.markingTypeEnum.name, + color: Colors.white, size: 10.sp), ), - Image.asset( - 'assets/images/icon_back_orange.png', - width: 8.r, - height: 8.r, + Expanded( + child: quickText(item.title, + size: 12.sp, + color: Color.fromRGBO(70, 70, 70, 1), + maxLines: 2), ), - ]), - ), - ], + SizedBox( + width: 5.r, + ), + Container( + padding: EdgeInsets.symmetric( + vertical: 1.r, horizontal: 5.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4.r), + border: Border.all( + width: 1.r, color: Color(0xFF4CC793)), + ), + child: Center( + child: Text( + item.subjectName, + style: TextStyle( + fontSize: 8.r, + color: Color(0xFF4CC793)), + ), + ), + ) + ], + ), + ), + + Container( + padding: EdgeInsets.symmetric(vertical: 6.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(6.r), + bottomRight: Radius.circular(6.r)), + color: Colors.white, + boxShadow: [ + BoxShadow( + color: const Color.fromRGBO(0, 0, 0, 0.15), + offset: Offset(0, -0.0001), //阴影y轴偏移量 + blurRadius: 4, //阴影模糊程度 + spreadRadius: 0, //阴影扩散程度 + ) + ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + alignment: Alignment.center, + child: quickText('详情', + color: Color(0xFFFFA115), size: 10.sp), + ), + Image.asset( + 'assets/images/icon_back_orange.png', + width: 8.r, + height: 8.r, + ), + ]), + ), + ], + ), ), ); }), @@ -139,7 +148,11 @@ class AnswerTrajectoryJob extends StatelessWidget { itemBuilder: (context, index) { JobTaskItem item = jobList[index]; return InkWell( - onTap: () {}, + onTap: () { + RouterManager.router.navigateTo(context, + '${RouterManager.answerTrajectoryJobDetailPath}?&jobId=${item.id}&jobName=${Uri.encodeComponent(item.title)}&genderName=${Uri.encodeComponent(item.genderName)}', + transition: getTransition()); + }, child: Container( margin: EdgeInsets.symmetric(vertical: 10.r), padding: EdgeInsets.only(top: 10.h), @@ -240,7 +253,7 @@ class AnswerTrajectoryJob extends StatelessWidget { Container( alignment: Alignment.center, child: quickText('详情', - color: Color(0xFFFFA115), size: 12.sp), + color: Color(0xFFFFA115), size: 10.sp), ), Image.asset( 'assets/images/icon_back_orange.png', diff --git a/marking_app/lib/routes/RouterManager.dart b/marking_app/lib/routes/RouterManager.dart index 0b0a0f0..197370c 100644 --- a/marking_app/lib/routes/RouterManager.dart +++ b/marking_app/lib/routes/RouterManager.dart @@ -14,6 +14,7 @@ import 'package:flutter/material.dart'; import 'package:marking_app/common/model/enum/marking_list_type.dart'; import 'package:marking_app/pages/common/startUpPage.dart'; import 'package:marking_app/pages/homework_correction/answer_trajectory.dart'; +import 'package:marking_app/pages/homework_correction/answer_trajectory_job_detail.dart'; import 'package:marking_app/pages/homework_correction/do_papers_job_exam.dart'; import 'package:marking_app/pages/homework_correction/index.dart'; import 'package:marking_app/pages/homework_correction/job_knowledge_points.dart'; @@ -86,6 +87,7 @@ class RouterManager { static const String jobKnowledgePointsPath = '/homework_correction/job_knowledge_points'; static const String jobKnowledgePointsDetailPath = '/homework_correction/job_knowledge_points_detail'; static const String answerTrajectoryPath = '/homework_correction/answer_trajectory'; + static const String answerTrajectoryJobDetailPath = '/homework_correction/answer_trajectory_job_detail'; // TheMine static final FluroRouter router = FluroRouter(); @@ -404,7 +406,15 @@ class RouterManager { }, ); - +//答题轨迹按作业详情 + static final _answerTrajectoryJobDetailPathHandler = Handler( + handlerFunc: (BuildContext? context, Map> params) { + int jobId = int.parse(params['jobId']![0]); + String jobName = params['jobName']![0]; + String genderName = params['genderName']![0]; + return AnswerTrajectoryJobDetail(jobId:jobId,jobName:jobName,genderName:genderName); + }, + ); // 开始阅卷页面 // static final _doMarkingPapers = Handler(handlerFunc: (BuildContext? context, Map> params) => MarkingPapers()); @@ -455,6 +465,7 @@ class RouterManager { router.define(jobKnowledgePointsPath, handler: _jobKnowledgePointsPathHandler, transitionType: TransitionType.material); router.define(jobKnowledgePointsDetailPath, handler: _jobKnowledgePointsDetailPathHandler, transitionType: TransitionType.material); router.define(answerTrajectoryPath, handler: _answerTrajectoryPathHandler, transitionType: TransitionType.material); + router.define(answerTrajectoryJobDetailPath, handler: _answerTrajectoryJobDetailPathHandler, transitionType: TransitionType.material); // getTransition() From aa9dd3d83cd63ba54419ebeeafef167d38ec93de Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Wed, 17 Apr 2024 18:15:37 +0800 Subject: [PATCH 20/28] =?UTF-8?q?=E8=BD=A8=E8=BF=B9=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .../lib/common/model/job/job_handwriting.dart | 55 ++++ .../quick_check_personal.dart | 93 ++++--- .../widget/answer_handwriting.dart | 255 ++++++++++++++++++ .../lib/utils/request/rest_client.dart | 121 ++++----- 5 files changed, 418 insertions(+), 107 deletions(-) create mode 100644 marking_app/lib/common/model/job/job_handwriting.dart create mode 100644 marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart diff --git a/.gitignore b/.gitignore index 16f39b3..64f504f 100644 --- a/.gitignore +++ b/.gitignore @@ -224,3 +224,4 @@ marking_app/lib/common/model/job/job_knowledge_detail_student.g.dart marking_app/lib/pages/homework_correction/job_home.g.dart marking_app/lib/common/model/marking/keyboard_assist_event.g.dart marking_app/lib/common/model/marking/marking_history_zoom_info.g.dart +marking_app/lib/common/model/job/job_handwriting.g.dart diff --git a/marking_app/lib/common/model/job/job_handwriting.dart b/marking_app/lib/common/model/job/job_handwriting.dart new file mode 100644 index 0000000..4d947fe --- /dev/null +++ b/marking_app/lib/common/model/job/job_handwriting.dart @@ -0,0 +1,55 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'job_handwriting.g.dart'; + +@JsonSerializable() +class JobHandwriting extends Object { + @JsonKey(name: 'lattices') + List lattices; + + @JsonKey(name: 'paperPicture') + String paperPicture; + + @JsonKey(name: 'pageNum') + int pageNum; + + @JsonKey(name: 'pageCount') + int pageCount; + + JobHandwriting( + this.lattices, + this.paperPicture, + this.pageNum, + this.pageCount, + ); + + factory JobHandwriting.fromJson(Map srcJson) => _$JobHandwritingFromJson(srcJson); + + Map toJson() => _$JobHandwritingToJson(this); +} + +@JsonSerializable() +class Lattices extends Object { + @JsonKey(name: 'stroke') + int stroke; + + @JsonKey(name: 'x') + int x; + + @JsonKey(name: 'y') + int y; + + @JsonKey(name: 'time') + int time; + + Lattices( + this.stroke, + this.x, + this.y, + this.time, + ); + + factory Lattices.fromJson(Map srcJson) => _$LatticesFromJson(srcJson); + + Map toJson() => _$LatticesToJson(this); +} diff --git a/marking_app/lib/pages/homework_correction/quick_check_personal.dart b/marking_app/lib/pages/homework_correction/quick_check_personal.dart index e883b0c..b6ef307 100644 --- a/marking_app/lib/pages/homework_correction/quick_check_personal.dart +++ b/marking_app/lib/pages/homework_correction/quick_check_personal.dart @@ -12,20 +12,19 @@ import 'package:marking_app/utils/common_utils.dart'; import 'package:marking_app/utils/request/rest_client.dart'; import 'package:marking_app/utils/toast_utils.dart'; +import 'widget/answer_handwriting.dart'; + class QuickCheckPersonal extends StatefulWidget { final int jobId; final int studentId; - const QuickCheckPersonal( - {Key? key, required this.jobId, required this.studentId}) - : super(key: key); + const QuickCheckPersonal({Key? key, required this.jobId, required this.studentId}) : super(key: key); @override State createState() => _QuickCheckPersonalState(); } -class _QuickCheckPersonalState extends State - with CommonMixin { +class _QuickCheckPersonalState extends State with CommonMixin { StudentDetails? studentInfo; void initState() { @@ -40,18 +39,16 @@ class _QuickCheckPersonalState extends State params['jobid'] = widget.jobId; // params['jobid'] = '521646983660101'; params['studentId'] = widget.studentId; - BaseStructureResult data = - await _client.getJobPersonalReport(params); - if(data.data!.studentId != null){ + BaseStructureResult data = await _client.getJobPersonalReport(params); + if (data.data!.studentId != null) { setState(() { studentInfo = data.data; }); - }else{ + } else { Navigator.pop(context); ToastUtils.showError('暂无数据'); } EasyLoading.dismiss(); - } @override @@ -74,7 +71,7 @@ class _QuickCheckPersonalState extends State ), actions: [ ReturnToHomepage(), - /* Title( + /* Title( color: Color(0xFF6888FD), child: Container( child: InkWell( @@ -89,20 +86,19 @@ class _QuickCheckPersonalState extends State alignment: Alignment.center, ), ),*/ - ], ), - body: SingleChildScrollView( child: Column( children: [ Padding( - padding: EdgeInsets.only(top: 14.r,left: 14.r), + padding: EdgeInsets.only(top: 14.r, left: 14.r), child: Row( children: [ InkWell( - onTap: (){ - RouterManager.router.navigateTo(context, '${RouterManager.jobPersonalDetailPath}?studentId=${widget.studentId}&studentName=${Uri.encodeComponent(studentInfo!.studentName!)}'); + onTap: () { + RouterManager.router.navigateTo(context, + '${RouterManager.jobPersonalDetailPath}?studentId=${widget.studentId}&studentName=${Uri.encodeComponent(studentInfo!.studentName!)}'); }, child: Container( width: 93.r, @@ -112,20 +108,33 @@ class _QuickCheckPersonalState extends State borderRadius: BorderRadius.circular(4.r), ), child: Center( - child: Text('历史查询',style: TextStyle(fontSize: 10.r,color: Color(0xFF2080F7)),), + child: Text( + '历史查询', + style: TextStyle(fontSize: 10.r, color: Color(0xFF2080F7)), + ), ), ), ), - SizedBox(width: 10.r,), - Container( - width: 93.r, - height: 28.r, - decoration: BoxDecoration( - color: Color(0xFFEDFFF7), - borderRadius: BorderRadius.circular(4.r), - ), - child: Center( - child: Text('原稿笔迹',style: TextStyle(fontSize: 10.r,color: Color(0xFF4CC793)),), + SizedBox( + width: 10.r, + ), + InkWell( + onTap: () { + showAnswerHandwriting(context, jobId: widget.jobId, studentId: widget.studentId); + }, + child: Container( + width: 93.r, + height: 28.r, + decoration: BoxDecoration( + color: Color(0xFFEDFFF7), + borderRadius: BorderRadius.circular(4.r), + ), + child: Center( + child: Text( + '原稿笔迹', + style: TextStyle(fontSize: 10.r, color: Color(0xFF4CC793)), + ), + ), ), ), ], @@ -147,22 +156,22 @@ class _QuickCheckPersonalState extends State children: [ Text( '客观题', - style: TextStyle( - fontSize: 14.sp, color: Color(0xFF5C5C5C),fontWeight: FontWeight.w600), + style: TextStyle(fontSize: 14.sp, color: Color(0xFF5C5C5C), fontWeight: FontWeight.w600), ), SizedBox( width: 10.r, ), Text( '${studentInfo!.kgValidRate}%', - style: TextStyle( - fontSize: 14.sp, color: Color(0xFF6888FD),fontWeight: FontWeight.w600), + style: TextStyle(fontSize: 14.sp, color: Color(0xFF6888FD), fontWeight: FontWeight.w600), ), ], ), - SizedBox(height: 10.r,), SizedBox( - height: studentInfo!.kgDetails.length>8?300.r:studentInfo!.kgDetails.length * 40.r + 40.r, + height: 10.r, + ), + SizedBox( + height: studentInfo!.kgDetails.length > 8 ? 300.r : studentInfo!.kgDetails.length * 40.r + 40.r, child: StudentKgTable( headList: ['题号', '学生答案', '标准答案'], bodyList: studentInfo!.kgDetails, @@ -171,7 +180,9 @@ class _QuickCheckPersonalState extends State ], ), ), - SizedBox(height: 15.r,), + SizedBox( + height: 15.r, + ), //主观题 Container( padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 10.r), @@ -188,24 +199,24 @@ class _QuickCheckPersonalState extends State children: [ Text( '主观题', - style: TextStyle( - fontSize: 14.sp, color: Color(0xFF5C5C5C),fontWeight: FontWeight.w600), + style: TextStyle(fontSize: 14.sp, color: Color(0xFF5C5C5C), fontWeight: FontWeight.w600), ), SizedBox( width: 10.r, ), Text( '${studentInfo!.zgValidRate}%', - style: TextStyle( - fontSize: 14.sp, color: Color(0xFF6888FD),fontWeight: FontWeight.w600), + style: TextStyle(fontSize: 14.sp, color: Color(0xFF6888FD), fontWeight: FontWeight.w600), ), ], ), - SizedBox(height: 10.r,), SizedBox( - height: studentInfo!.zgDetails.length>8?300.r:studentInfo!.zgDetails.length * 40.r + 40.r, + height: 10.r, + ), + SizedBox( + height: studentInfo!.zgDetails.length > 8 ? 300.r : studentInfo!.zgDetails.length * 40.r + 40.r, child: StudentZgTable( - headList: ['题号', '用时', '学生答案','批注结果','批注'], + headList: ['题号', '用时', '学生答案', '批注结果', '批注'], bodyList: studentInfo!.zgDetails, ), ) diff --git a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart new file mode 100644 index 0000000..8bf8322 --- /dev/null +++ b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart @@ -0,0 +1,255 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:marking_app/common/mixin/common.dart'; +import 'package:marking_app/common/model/job/job_handwriting.dart'; +import 'package:marking_app/utils/index.dart'; +import 'package:marking_app/utils/my_text.dart'; + +/// 学生答题轨迹 +class AnswerHandwriting extends Dialog { + final int jobId; + final int studentId; + final int? pageNum; + final int? questionNo; + final Function closeCall; + const AnswerHandwriting({required this.jobId, required this.studentId, required this.closeCall, this.pageNum, this.questionNo}); + + @override + Widget build(BuildContext context) { + return Center( + child: Container( + // color: Color.fromRGBO(0, 0, 0, 0.6), + width: ScreenUtil().screenWidth - 60.w, + height: ScreenUtil().screenHeight - 160.h, + child: AnswerHandwritingMainBox(jobId: jobId, studentId: studentId, pageNum: pageNum, questionNo: questionNo, closeCall: closeCall), + ), + ); + } +} + +Future showAnswerHandwriting(BuildContext context, {required int jobId, required int studentId, int? pageNum}) async { + return showDialog( + context: context, + builder: (BuildContext context) => AnswerHandwriting( + jobId: jobId, + studentId: studentId, + pageNum: pageNum, + closeCall: () => Navigator.of(context).pop(), + ), + ); +} + +// 主图 +class AnswerHandwritingMainBox extends HookWidget { + const AnswerHandwritingMainBox({ + required this.jobId, + required this.studentId, + required this.closeCall, + this.pageNum, + this.questionNo, + Key? key, + }) : super(key: key); + + final int jobId; + final int studentId; + final int? pageNum; + final int? questionNo; + final Function closeCall; + + @override + Widget build(BuildContext context) { + var _useStateModel = UseMainBoxState.use(jobId, studentId, pageNum, questionNo); + + useValueChanged(_useStateModel.handwritingData.value, (_, __) { + var theData = _useStateModel.handwritingData.value; + _useStateModel.pageNum.value = theData?.pageNum; + _useStateModel.pageCount.value = theData?.pageCount ?? 0; + }); + + useValueChanged(_useStateModel.pageNum.value, (oldVal, __) { + if (oldVal != null && oldVal != _useStateModel.pageNum.value) _useStateModel.getData().catchError((e) => closeCall()); + }); + + useEffect(() { + _useStateModel.getData().catchError((e) => closeCall()); + _useStateModel.imageKey.value = UniqueKey(); + return () {}; + }, []); + + JobHandwriting? _data = _useStateModel.handwritingData.value; + print('这里是build:${_useStateModel.pageNum.value}'); + + if (_data == null) return Container(); + return Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Stack( + children: [ + Container( + child: CachedNetworkImage( + key: _useStateModel.imageKey.value, + fit: BoxFit.contain, + imageUrl: _data?.paperPicture ?? '', + imageBuilder: (context, imageProvider) { + return Image(image: imageProvider, fit: BoxFit.fitWidth); + }, + placeholder: (context, url) => Center(child: SpinKitWaveSpinner(color: Theme.of(context).primaryColor, size: 50.r)), + errorWidget: (context, url, error) { + return Center( + child: GestureDetector( + onTap: () => (_useStateModel.imageKey.value = UniqueKey()), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset('assets/images/test_paper_loading_failed.png'), + quickText('加载失败,点击重试', color: Color.fromRGBO(148, 163, 182, 1), size: 12.sp), + ], + ), + ), + ); + }, + ), + ), + if (_useStateModel.handwritingData.value != null && _useStateModel.pageNum.value != null && _useStateModel.pageNum.value! > 1) + Positioned( + left: 3.w, + top: 280.h, + child: FloatingActionButton( + heroTag: '点击前往上一题', + tooltip: '点击前往上一题', + focusColor: Theme.of(context).primaryColor, + backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1), + elevation: 6.r, + onPressed: () => easyThrottle('answer_handwriting_previous', () { + _useStateModel.pageNum.value = _useStateModel.pageNum.value! - 1; + }), + child: Icon(Icons.arrow_back_ios, color: Colors.white, size: 22.sp), + ), + ), + // 下一题 按钮 + if (_useStateModel.handwritingData.value != null && + _useStateModel.pageNum.value != null && + _useStateModel.pageNum.value! < _useStateModel.pageCount.value) + Positioned( + right: 3.w, + top: 280.h, + child: FloatingActionButton( + heroTag: '点击前往下一题', + tooltip: '点击前往下一题', + elevation: 6.r, + backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1), + onPressed: () => easyThrottle('answer_handwriting_next', () { + _useStateModel.pageNum.value = _useStateModel.pageNum.value! + 1; + }), + child: Icon(Icons.arrow_forward_ios, color: Colors.white, size: 22.sp), + ), + ), + ], + ), + Expanded( + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h), + alignment: Alignment.center, + color: Color.fromRGBO(0, 0, 0, 0.5), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + InkWell( + onTap: () {}, + child: Icon( + // Icons.play_circle_outline + Icons.pause_circle_outline, + color: Colors.white, + size: 28.r, + ), + ), + SizedBox(width: 6.w), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + height: 20.h, + color: Theme.of(context).primaryColor, + ), + SizedBox(height: 4.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + quickText('累计停顿:2次', color: Colors.white, size: 7.sp), + quickText('04:30', color: Colors.white, size: 7.sp), + ], + ) + ], + ), + ), + SizedBox(width: 16.w), + InkWell( + onTap: () {}, + child: Container( + // alignment: Alignment., + padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h), + decoration: BoxDecoration(color: Color.fromRGBO(182, 197, 250, 1), borderRadius: BorderRadius.circular(4.r)), + child: quickText('原速播放', color: Color.fromRGBO(79, 114, 244, 1), size: 10.sp, align: TextAlign.center), + ), + ), + ], + ), + ), + ), + ], + ); + } +} + +class UseMainBoxState with CommonMixin { + final int jobId; + final int studentId; + final int? questionNo; + final ValueNotifier pageNum; + final ValueNotifier pageCount; + final ValueNotifier handwritingData; + final ValueNotifier imageKey; + UseMainBoxState._({ + required this.jobId, + required this.studentId, + required this.pageNum, + required this.handwritingData, + required this.questionNo, + required this.pageCount, + required this.imageKey, + }); + + // 工厂构造函数 + factory UseMainBoxState.use(int jobId, int studentId, [int? pageNum, int? questionNo]) { + return UseMainBoxState._( + jobId: jobId, + studentId: studentId, + questionNo: questionNo, + pageNum: useState(pageNum), + handwritingData: useState(null), + pageCount: useState(0), + imageKey: useState(null), + ); + } + + Future getData() async { + try { + ToastUtils.showLoading(); + var _client = await getClient(); + var res = await _client.getHandwriting(jobId, studentId, questionNo, pageNum.value); + if (res?.success ?? false) { + handwritingData.value = res!.data; + return; + } + Future.delayed(Duration(seconds: 1), () => ToastUtils.showError(res?.message ?? '笔记数据请求失败')); + } catch (e) { + } finally { + ToastUtils.dismiss(); + } + } +} diff --git a/marking_app/lib/utils/request/rest_client.dart b/marking_app/lib/utils/request/rest_client.dart index 6d8789a..6737395 100644 --- a/marking_app/lib/utils/request/rest_client.dart +++ b/marking_app/lib/utils/request/rest_client.dart @@ -19,6 +19,7 @@ import 'package:marking_app/common/model/job/job_data_report.dart'; import 'package:marking_app/common/model/job/job_do_marking_status_info.dart'; import 'package:marking_app/common/model/job/job_fav_student.dart'; import 'package:marking_app/common/model/job/job_favorite_model.dart'; +import 'package:marking_app/common/model/job/job_handwriting.dart'; import 'package:marking_app/common/model/job/job_knowledge_detail_student.dart'; import 'package:marking_app/common/model/job/job_knowledge_points.dart'; import 'package:marking_app/common/model/job/job_knowledge_points_detail.dart'; @@ -74,8 +75,7 @@ abstract class RestClient { // 最新版本 @the_retrofit.GET("/api/version/latest?mobileTypeEnum={mobileTypeEnum}") - Future> getLatestVersion( - @the_retrofit.Path("mobileTypeEnum") int mobileTypeEnum); // 1 安卓 2 ios + Future> getLatestVersion(@the_retrofit.Path("mobileTypeEnum") int mobileTypeEnum); // 1 安卓 2 ios // 用户登录 /auth/login/exam-marking/user-mobile @the_retrofit.POST("/auth/login/exam-marking/user") @@ -91,8 +91,7 @@ abstract class RestClient { // 阅卷列表 => 分页获取 @the_retrofit.GET("/api/marking/list") - Future>> getMarkingsByPage( - @the_retrofit.Queries() MarkingListParams params); + Future>> getMarkingsByPage(@the_retrofit.Queries() MarkingListParams params); // /api/marking/list @@ -117,13 +116,11 @@ abstract class RestClient { // 阅卷 => 获取考试试题 @the_retrofit.GET("/api/marking/question") - Future> getTestQuestionsOfExam( - @the_retrofit.Queries() MarkingTextQuestionParams params); + Future> getTestQuestionsOfExam(@the_retrofit.Queries() MarkingTextQuestionParams params); // 阅卷 => 获取考试tab(试题批次) @the_retrofit.GET("/api/marking/{markingUserId}/tab") - Future>> getTestQuestionsOfTab( - @the_retrofit.Path("markingUserId") int markingUserId); + Future>> getTestQuestionsOfTab(@the_retrofit.Path("markingUserId") int markingUserId); // 阅卷 => 单个试题Tag阅卷详情 @the_retrofit.GET("/api/marking/{markingUserId}/progress") @@ -137,16 +134,15 @@ abstract class RestClient { // 阅卷 => 获取考试tab下某次试题 @the_retrofit.GET("/api/marking/{markingUserId}/detail") - Future> getTabOfExam(@the_retrofit.Path("markingUserId") int markingUserId, - @the_retrofit.Queries() MarkingTextQuestionTabParams params); + Future> getTabOfExam( + @the_retrofit.Path("markingUserId") int markingUserId, @the_retrofit.Queries() MarkingTextQuestionTabParams params); // 阅卷 => 提交考试试题 @the_retrofit.PUT("/api/marking") Future> submitTestQuestionsOfExam(@the_retrofit.Body() SubmitExamParams params); @the_retrofit.PUT("/api/marking/error") - Future> submitTestQuestionsOfExamAbnormal( - @the_retrofit.Body() SubmitExamAbnormalParams params); + Future> submitTestQuestionsOfExamAbnormal(@the_retrofit.Body() SubmitExamAbnormalParams params); // 阅卷 => 提交考试试题 @the_retrofit.PUT("/api/marking/review") @@ -158,8 +154,7 @@ abstract class RestClient { // 阅卷 => 结束阅卷 @the_retrofit.GET("/api/marking/original-paper") - Future>> getViewOriginalVolume( - @the_retrofit.Query("markingUserDetailId") String markingUserDetailId); + Future>> getViewOriginalVolume(@the_retrofit.Query("markingUserDetailId") String markingUserDetailId); // 阅卷 => 查看答案 @the_retrofit.GET("/api/marking/answer") @@ -185,25 +180,21 @@ abstract class RestClient { // 阅卷 => 获取异常详细信息 @the_retrofit.GET("/api/marking/error-info") - Future> getMarkingQuestionsErrorInfo( - @the_retrofit.Query("markingUserDetailId") int id); + Future> getMarkingQuestionsErrorInfo(@the_retrofit.Query("markingUserDetailId") int id); // 阅卷 => 获取仲裁详细信息 @the_retrofit.GET("/api/marking/history-score") - Future>> getArbitrateOfHistoryScore( - @the_retrofit.Query("markingUserDetailId") int id); + Future>> getArbitrateOfHistoryScore(@the_retrofit.Query("markingUserDetailId") int id); // 阅卷 => 获取仲裁详细信息 @the_retrofit.GET("/api/marking/rating-info") - Future>> getMarkingRatingInfo( - @the_retrofit.Query("markingUserId") int id); + Future>> getMarkingRatingInfo(@the_retrofit.Query("markingUserId") int id); // ------------------------------------------ 作业 ------------------------------------------ // 作业 => 作业列表 @the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Task") - Future>> getJobsByPage( - @the_retrofit.Queries() MarkingListParams params); + Future>> getJobsByPage(@the_retrofit.Queries() MarkingListParams params); // 作业 => 批改获取tabs @the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Task/tabs") @@ -211,13 +202,11 @@ abstract class RestClient { // 作业 => 批改获取tabs @the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Marking/students") - Future>> getJobWithStudents( - @the_retrofit.Queries() JobConcernedWithStudentParams params); + Future>> getJobWithStudents(@the_retrofit.Queries() JobConcernedWithStudentParams params); // 作业 => 获取考试tab下某次试题 @the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Task/detail") - Future> getJobTabOfExam( - @the_retrofit.Queries() MarkingTextQuestionJobTabParams params); + Future> getJobTabOfExam(@the_retrofit.Queries() MarkingTextQuestionJobTabParams params); // 作业 => 提交 @the_retrofit.POST("${RequestConfig.hwProxyKeywords}/api/Task") @@ -229,8 +218,7 @@ abstract class RestClient { // 作业 => 获取考试tab下某次试题 @the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Task/questions") - Future>> toGoreviewAgainPage( - @the_retrofit.Queries() ReviewAgainListParams params); + Future>> toGoreviewAgainPage(@the_retrofit.Queries() ReviewAgainListParams params); // 作业 => 获取参考答案 @the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Task/answer") @@ -241,8 +229,7 @@ abstract class RestClient { // 作业 => 上传图片请求参数 @the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Upload") - Future> getUploadFile( - @the_retrofit.Queries() UploadFileInterfaceConfigParams params); + Future> getUploadFile(@the_retrofit.Queries() UploadFileInterfaceConfigParams params); // 作业 => 获取参考答案 @the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Dpc/studentAnswerHandwriting") @@ -251,18 +238,16 @@ abstract class RestClient { // 作业 => 查询作业是否收藏 @the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Dpc/collect") - Future> getJobCollect(@the_retrofit.Query("taskId") int taskId, - @the_retrofit.Query("studentId") int studentId, @the_retrofit.Query("paperId") int paperId); + Future> getJobCollect( + @the_retrofit.Query("taskId") int taskId, @the_retrofit.Query("studentId") int studentId, @the_retrofit.Query("paperId") int paperId); // 作业 => 作业优先批阅取消 @the_retrofit.POST("/api/read/cancel-job-read-level") - Future> jobPriorityReviewCancel( - @the_retrofit.Field("jobId") int jobId, @the_retrofit.Field("studentId") int studentId); + Future> jobPriorityReviewCancel(@the_retrofit.Field("jobId") int jobId, @the_retrofit.Field("studentId") int studentId); // 作业 => 作业优先批阅加入 @the_retrofit.POST("/api/read/join-read-level") - Future jobPriorityReviewJoin( - @the_retrofit.Field("jobId") int jobId, @the_retrofit.Field("studentId") int studentId); + Future jobPriorityReviewJoin(@the_retrofit.Field("jobId") int jobId, @the_retrofit.Field("studentId") int studentId); // 作业 => 查询作业是否收藏 @the_retrofit.POST("${RequestConfig.hwProxyKeywords}/api/Dpc/collect") @@ -297,13 +282,11 @@ abstract class RestClient { // 作业 => 列表 ==> 参与班级列表 @the_retrofit.GET("${RequestConfig.hwProxyKeywords}/api/Task/tasks") - Future>> getJobListParticipateInClass( - @the_retrofit.Query("markingId") int jobId); + Future>> getJobListParticipateInClass(@the_retrofit.Query("markingId") int jobId); // 作业 => 作业收藏数量 @the_retrofit.GET("/dpc-api/api/read/job-favorite-count-by-class") - Future>> getListOfJobFavoriteNumber( - @the_retrofit.Query("jobid") int jobId); + Future>> getListOfJobFavoriteNumber(@the_retrofit.Query("jobid") int jobId); // 作业 => 作业收藏列表 @the_retrofit.GET("/api/jobs/fav-student-jobs") @@ -316,13 +299,11 @@ abstract class RestClient { // 作业 => 作业收藏列表 @the_retrofit.POST("${RequestConfig.hwProxyKeywords}/dpc-api/api/read/cancel-favorite") - Future> toJobCancelFavorite( - @the_retrofit.Field() int jobId, @the_retrofit.Field() int studentId); + Future> toJobCancelFavorite(@the_retrofit.Field() int jobId, @the_retrofit.Field() int studentId); // 作业 => 数据快查 @the_retrofit.GET("/api/read/job-data-center-report") - Future> getJobDataCenterReport( - @the_retrofit.Queries() Map params); + Future> getJobDataCenterReport(@the_retrofit.Queries() Map params); // 作业 => 数据快查--个人 @the_retrofit.GET("/api/read/job-data-center-student-report") @@ -330,8 +311,7 @@ abstract class RestClient { // 作业 => 优先批阅,学生分组列表 @the_retrofit.GET("/api/read/job-read-level-student-groups") - Future>> getJobLevelStudentGroups( - @the_retrofit.Query("account") String account); + Future>> getJobLevelStudentGroups(@the_retrofit.Query("account") String account); // 作业 => 优先批阅,优先批阅列表 @the_retrofit.GET("/api/read/job-read-level") @@ -344,44 +324,53 @@ abstract class RestClient { // 作业 => 取消收藏 @the_retrofit.POST("/api/jobs/de-fav-student-job") - Future getJobDeFavorites(@the_retrofit.Field("jobId") int jobId, - @the_retrofit.Field("studentId") int studentId, @the_retrofit.Field("questionPage") int questionPage); + Future getJobDeFavorites( + @the_retrofit.Field("jobId") int jobId, @the_retrofit.Field("studentId") int studentId, @the_retrofit.Field("questionPage") int questionPage); // 作业 => 学生作业详情历史 @the_retrofit.GET("/api/read/student-job-history") Future> getStudentJobHistory( - @the_retrofit.Query("StudentId") int studentId, - @the_retrofit.Query("IsPaper") bool isPaper, - @the_retrofit.Query("DateStart") String? dateStart, - @the_retrofit.Query("DateEnd") String? dateEnd, - @the_retrofit.Query("Page") int page, - @the_retrofit.Query("PageSize") int pageSize, - ); + @the_retrofit.Query("StudentId") int studentId, + @the_retrofit.Query("IsPaper") bool isPaper, + @the_retrofit.Query("DateStart") String? dateStart, + @the_retrofit.Query("DateEnd") String? dateEnd, + @the_retrofit.Query("Page") int page, + @the_retrofit.Query("PageSize") int pageSize, + ); // 作业 => 知识点掌握 @the_retrofit.GET("/api/jobs/knowledge-report") Future>> getKnowledgeReport( - @the_retrofit.Query("dateStart") String? dateStart, - @the_retrofit.Query("dateEnd") String? dateEnd, - @the_retrofit.Query("knowledgeName") String? knowledgeName, - ); + @the_retrofit.Query("dateStart") String? dateStart, + @the_retrofit.Query("dateEnd") String? dateEnd, + @the_retrofit.Query("knowledgeName") String? knowledgeName, + ); // 作业 => 知识点掌握详情 @the_retrofit.GET("/api/jobs/knowledge-detail-report") Future>> getKnowledgeReportDetail( - @the_retrofit.Query("KnowledgeId") int knowledgeId, - ); + @the_retrofit.Query("KnowledgeId") int knowledgeId, + ); // 作业 => 知识点掌握详情人员名单 @the_retrofit.GET("/api/jobs/knowledge-question-detail/{questionid}") Future>> getKnowledgeStudent( - @the_retrofit.Path("questionid") int questionid, - ); + @the_retrofit.Path("questionid") int questionid, + ); // 作业 => 知识点掌握详情原卷图 @the_retrofit.GET("/api/jobs/question-paper-img/{sectionid}/{questionno}") Future> getKnowledgeImg( - @the_retrofit.Path("sectionid") int questionid, - @the_retrofit.Path("questionno") String questionno, - ); + @the_retrofit.Path("sectionid") int questionid, + @the_retrofit.Path("questionno") String questionno, + ); + + // 作业 => 获取学生原稿笔记 + @the_retrofit.GET("/api/jobs/student-paper-handwriting") + Future?> getHandwriting( + @the_retrofit.Query("jobId") int jobId, + @the_retrofit.Query("studentId") int studentId, + @the_retrofit.Query("questionNo") int? questionNo, + @the_retrofit.Query("pageNum") int? pageNum, + ); } From 8c10e6eb4de40a07c3c0eb008764e1f11d9c9421 Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Wed, 24 Apr 2024 13:46:19 +0800 Subject: [PATCH 21/28] no message --- .gitignore | 2 + .../common/model/job/gesture_recording.dart | 19 + .../lib/common/model/job/job_handwriting.dart | 21 +- .../model/job/test_questions_image_info.dart | 15 +- .../pages/homework_correction/job_home.dart | 21 +- ...ndwriting_drawing_trajectory_provider.dart | 18 + .../quick_check_personal.dart | 12 +- .../widget/answer_handwriting.dart | 893 +++++++++++++++--- marking_app/lib/utils/my_time_util.dart | 65 ++ 9 files changed, 912 insertions(+), 154 deletions(-) create mode 100644 marking_app/lib/pages/homework_correction/providers/handwriting_drawing_trajectory_provider.dart create mode 100644 marking_app/lib/utils/my_time_util.dart diff --git a/.gitignore b/.gitignore index 64f504f..166ba42 100644 --- a/.gitignore +++ b/.gitignore @@ -225,3 +225,5 @@ marking_app/lib/pages/homework_correction/job_home.g.dart marking_app/lib/common/model/marking/keyboard_assist_event.g.dart marking_app/lib/common/model/marking/marking_history_zoom_info.g.dart marking_app/lib/common/model/job/job_handwriting.g.dart +marking_app/lib/utils/my_time_util.g.dart +marking_app/lib/pages/homework_correction/widget/answer_handwriting.g.dart diff --git a/marking_app/lib/common/model/job/gesture_recording.dart b/marking_app/lib/common/model/job/gesture_recording.dart index a2ea382..5e36be8 100644 --- a/marking_app/lib/common/model/job/gesture_recording.dart +++ b/marking_app/lib/common/model/job/gesture_recording.dart @@ -14,11 +14,30 @@ class GestureRecording { bool scopeBox; + int intervalTime; // 间隔时间 + GestureRecording({ required this.eraser, required this.annotationSwitch, this.data, this.usageTime, this.scopeBox = false, + this.intervalTime = 0, + }); +} + +/** + * 手势记录(原稿笔记还原) + */ +class GestureHandwritingRecording { + int stroke; + int usageTime; // 用时 + Offset data; + int intervalTime; // 间隔时间 + GestureHandwritingRecording({ + required this.stroke, + required this.data, + required this.usageTime, + required this.intervalTime, }); } diff --git a/marking_app/lib/common/model/job/job_handwriting.dart b/marking_app/lib/common/model/job/job_handwriting.dart index 4d947fe..72931c9 100644 --- a/marking_app/lib/common/model/job/job_handwriting.dart +++ b/marking_app/lib/common/model/job/job_handwriting.dart @@ -16,12 +16,7 @@ class JobHandwriting extends Object { @JsonKey(name: 'pageCount') int pageCount; - JobHandwriting( - this.lattices, - this.paperPicture, - this.pageNum, - this.pageCount, - ); + JobHandwriting(this.lattices, this.paperPicture, this.pageNum, this.pageCount); factory JobHandwriting.fromJson(Map srcJson) => _$JobHandwritingFromJson(srcJson); @@ -34,20 +29,18 @@ class Lattices extends Object { int stroke; @JsonKey(name: 'x') - int x; + double x; @JsonKey(name: 'y') - int y; + double y; @JsonKey(name: 'time') int time; - Lattices( - this.stroke, - this.x, - this.y, - this.time, - ); + @JsonKey(name: 'intervalTime') + int intervalTime; + + Lattices(this.stroke, this.x, this.y, this.time, [this.intervalTime = 0]); factory Lattices.fromJson(Map srcJson) => _$LatticesFromJson(srcJson); diff --git a/marking_app/lib/common/model/job/test_questions_image_info.dart b/marking_app/lib/common/model/job/test_questions_image_info.dart index fed08ac..e9a1e7c 100644 --- a/marking_app/lib/common/model/job/test_questions_image_info.dart +++ b/marking_app/lib/common/model/job/test_questions_image_info.dart @@ -36,12 +36,7 @@ class TestQuestionsImageInfo extends Object { double? imageHeightOffsetend; TestQuestionsImageInfo( - {required this.width, - required this.height, - required this.url, - required this.boxWidth, - required this.boxHeight, - this.pixelRatio = 1}) { + {required this.width, required this.height, required this.url, required this.boxWidth, required this.boxHeight, this.pixelRatio = 1}) { // print('图片宽度:$width'); // print('图片高度:$height'); @@ -60,6 +55,14 @@ class TestQuestionsImageInfo extends Object { } } + // 重新计算 + void calculateStartAndEndHeight([double otherHeight = 0]) { + if (scaleHeight != null) { + imageHeightOffsetStart = (boxHeight - (scaleHeight! + otherHeight)) / 2; + imageHeightOffsetend = imageHeightOffsetStart! + scaleHeight!; + } + } + factory TestQuestionsImageInfo.fromJson(Map srcJson) => _$TestQuestionsImageInfoFromJson(srcJson); Map toJson() => _$TestQuestionsImageInfoToJson(this); diff --git a/marking_app/lib/pages/homework_correction/job_home.dart b/marking_app/lib/pages/homework_correction/job_home.dart index a442f57..9e067a7 100644 --- a/marking_app/lib/pages/homework_correction/job_home.dart +++ b/marking_app/lib/pages/homework_correction/job_home.dart @@ -76,14 +76,17 @@ class _JobHomeState extends State with CommonMixin, EventBusMixin, Auto child: ListView( children: [ Container( - height: 200.h, - width: double.infinity, - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/images/job_home_top_bgm.png'), - fit: BoxFit.fill, // 完全填充 - ), + constraints: BoxConstraints( + minHeight: 200.h, + maxWidth: double.infinity, ), + // decoration: BoxDecoration( + // image: DecorationImage( + // image: AssetImage('assets/images/job_home_top_bgm.png'), + // fit: BoxFit.fitWidth, // 完全填充 + // ), + // ), + child: Image.asset('assets/images/job_home_top_bgm.png', fit: BoxFit.fitWidth), ), SizedBox(height: 30.h), SlidingData([ @@ -104,8 +107,8 @@ class _JobHomeState extends State with CommonMixin, EventBusMixin, Auto navigationUrl: '${RouterManager.jobStudentGroupPath}?page=set', ) ], 0), - spaceWidth, - $TermRow([EntranceModel(title: '批阅设置', image: 'assets/images/job_home_marking_set.png', navigationUrl: '')], 0), + // spaceWidth, + // $TermRow([EntranceModel(title: '批阅设置', image: 'assets/images/job_home_marking_set.png', navigationUrl: '')], 0), ], ), ), diff --git a/marking_app/lib/pages/homework_correction/providers/handwriting_drawing_trajectory_provider.dart b/marking_app/lib/pages/homework_correction/providers/handwriting_drawing_trajectory_provider.dart new file mode 100644 index 0000000..30f40bf --- /dev/null +++ b/marking_app/lib/pages/homework_correction/providers/handwriting_drawing_trajectory_provider.dart @@ -0,0 +1,18 @@ +/// 原稿作业回显 +// 回显批注轨迹 + +import 'package:marking_app/common/model/job/gesture_recording.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:marking_app/common/mixin/common.dart'; + +final jobHandwritingDrawingTrajectoryProvider = + StateNotifierProvider>( + (ref) => JobHandwritingDrawingTrajectoryProviderHandle([])); + +class JobHandwritingDrawingTrajectoryProviderHandle extends StateNotifier> with CommonMixin { + JobHandwritingDrawingTrajectoryProviderHandle(List progress) : super(progress); + + setVal(List val) { + state = val; + } +} diff --git a/marking_app/lib/pages/homework_correction/quick_check_personal.dart b/marking_app/lib/pages/homework_correction/quick_check_personal.dart index b6ef307..0c8fe89 100644 --- a/marking_app/lib/pages/homework_correction/quick_check_personal.dart +++ b/marking_app/lib/pages/homework_correction/quick_check_personal.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:marking_app/common/mixin/common.dart'; import 'package:marking_app/common/model/common/base_structure_result.dart'; import 'package:marking_app/common/model/job/job_data_report.dart'; @@ -12,19 +13,20 @@ import 'package:marking_app/utils/common_utils.dart'; import 'package:marking_app/utils/request/rest_client.dart'; import 'package:marking_app/utils/toast_utils.dart'; +import 'providers/handwriting_drawing_trajectory_provider.dart'; import 'widget/answer_handwriting.dart'; -class QuickCheckPersonal extends StatefulWidget { +class QuickCheckPersonal extends StatefulHookConsumerWidget { final int jobId; final int studentId; const QuickCheckPersonal({Key? key, required this.jobId, required this.studentId}) : super(key: key); @override - State createState() => _QuickCheckPersonalState(); + ConsumerState createState() => _QuickCheckPersonalState(); } -class _QuickCheckPersonalState extends State with CommonMixin { +class _QuickCheckPersonalState extends ConsumerState with CommonMixin { StudentDetails? studentInfo; void initState() { @@ -120,7 +122,9 @@ class _QuickCheckPersonalState extends State with CommonMixi ), InkWell( onTap: () { - showAnswerHandwriting(context, jobId: widget.jobId, studentId: widget.studentId); + showAnswerHandwriting(context, jobId: widget.jobId, studentId: widget.studentId).then((value) { + ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); + }); }, child: Container( width: 93.r, diff --git a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart index 8bf8322..bb5591a 100644 --- a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart +++ b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart @@ -1,12 +1,25 @@ +import 'dart:async'; + import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:functional_widget_annotation/functional_widget_annotation.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:marking_app/common/mixin/common.dart'; import 'package:marking_app/common/model/job/job_handwriting.dart'; +import 'package:marking_app/common/model/job/test_questions_image_info.dart'; +import 'package:marking_app/pages/common/event_bus_mixin.dart'; +import 'package:marking_app/pages/homework_correction/hooks/use_cached_img_refresh.dart'; import 'package:marking_app/utils/index.dart'; import 'package:marking_app/utils/my_text.dart'; +import 'package:marking_app/utils/my_time_util.dart'; + +import '../../../common/model/job/gesture_recording.dart'; +import '../providers/handwriting_drawing_trajectory_provider.dart'; + +part 'answer_handwriting.g.dart'; /// 学生答题轨迹 class AnswerHandwriting extends Dialog { @@ -21,10 +34,15 @@ class AnswerHandwriting extends Dialog { Widget build(BuildContext context) { return Center( child: Container( - // color: Color.fromRGBO(0, 0, 0, 0.6), - width: ScreenUtil().screenWidth - 60.w, - height: ScreenUtil().screenHeight - 160.h, - child: AnswerHandwritingMainBox(jobId: jobId, studentId: studentId, pageNum: pageNum, questionNo: questionNo, closeCall: closeCall), + width: ScreenUtil().screenWidth - 60.r, + alignment: Alignment.center, + child: AnswerHandwritingMainBox( + jobId: jobId, + studentId: studentId, + pageNum: pageNum, + questionNo: questionNo, + closeCall: closeCall, + ), ), ); } @@ -67,6 +85,12 @@ class AnswerHandwritingMainBox extends HookWidget { var theData = _useStateModel.handwritingData.value; _useStateModel.pageNum.value = theData?.pageNum; _useStateModel.pageCount.value = theData?.pageCount ?? 0; + _useStateModel.playPause.value = false; + _useStateModel.constantFastSpeed.value = false; + Future.delayed(Duration.zero, () { + _useStateModel.handwritingKey.currentState?.ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); + }); + _useStateModel.handwritingDetail.value = _useStateModel.getHandwritingDetail(theData); }); useValueChanged(_useStateModel.pageNum.value, (oldVal, __) { @@ -75,132 +99,42 @@ class AnswerHandwritingMainBox extends HookWidget { useEffect(() { _useStateModel.getData().catchError((e) => closeCall()); - _useStateModel.imageKey.value = UniqueKey(); return () {}; }, []); JobHandwriting? _data = _useStateModel.handwritingData.value; - print('这里是build:${_useStateModel.pageNum.value}'); + HandwritingInfo? _dataDetail = _useStateModel.handwritingDetail.value; - if (_data == null) return Container(); + if (_data == null || _dataDetail == null) return Container(); + print('数据长度:${_data.lattices.length}'); return Column( - mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, children: [ Stack( + alignment: const FractionalOffset(0, 0.5), children: [ - Container( - child: CachedNetworkImage( - key: _useStateModel.imageKey.value, - fit: BoxFit.contain, - imageUrl: _data?.paperPicture ?? '', - imageBuilder: (context, imageProvider) { - return Image(image: imageProvider, fit: BoxFit.fitWidth); - }, - placeholder: (context, url) => Center(child: SpinKitWaveSpinner(color: Theme.of(context).primaryColor, size: 50.r)), - errorWidget: (context, url, error) { - return Center( - child: GestureDetector( - onTap: () => (_useStateModel.imageKey.value = UniqueKey()), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Image.asset('assets/images/test_paper_loading_failed.png'), - quickText('加载失败,点击重试', color: Color.fromRGBO(148, 163, 182, 1), size: 12.sp), - ], - ), - ), - ); - }, - ), + // 图片展示主框 + HandwritingDrawBox( + _data.paperPicture, + _dataDetail, + key: _useStateModel.handwritingKey, + ), + $PageNumberBox(_data.pageNum), + // 上一页按钮 + $PreviousNutton( + _useStateModel.pageNum.value, + () => _useStateModel.pageNum.value = _useStateModel.pageNum.value! - 1, + ), + // 下一题按钮 + $NextPageButton( + _useStateModel.pageNum.value, + _useStateModel.pageCount.value, + () => _useStateModel.pageNum.value = _useStateModel.pageNum.value! + 1, ), - if (_useStateModel.handwritingData.value != null && _useStateModel.pageNum.value != null && _useStateModel.pageNum.value! > 1) - Positioned( - left: 3.w, - top: 280.h, - child: FloatingActionButton( - heroTag: '点击前往上一题', - tooltip: '点击前往上一题', - focusColor: Theme.of(context).primaryColor, - backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1), - elevation: 6.r, - onPressed: () => easyThrottle('answer_handwriting_previous', () { - _useStateModel.pageNum.value = _useStateModel.pageNum.value! - 1; - }), - child: Icon(Icons.arrow_back_ios, color: Colors.white, size: 22.sp), - ), - ), - // 下一题 按钮 - if (_useStateModel.handwritingData.value != null && - _useStateModel.pageNum.value != null && - _useStateModel.pageNum.value! < _useStateModel.pageCount.value) - Positioned( - right: 3.w, - top: 280.h, - child: FloatingActionButton( - heroTag: '点击前往下一题', - tooltip: '点击前往下一题', - elevation: 6.r, - backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1), - onPressed: () => easyThrottle('answer_handwriting_next', () { - _useStateModel.pageNum.value = _useStateModel.pageNum.value! + 1; - }), - child: Icon(Icons.arrow_forward_ios, color: Colors.white, size: 22.sp), - ), - ), ], ), - Expanded( - child: Container( - padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h), - alignment: Alignment.center, - color: Color.fromRGBO(0, 0, 0, 0.5), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - InkWell( - onTap: () {}, - child: Icon( - // Icons.play_circle_outline - Icons.pause_circle_outline, - color: Colors.white, - size: 28.r, - ), - ), - SizedBox(width: 6.w), - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - height: 20.h, - color: Theme.of(context).primaryColor, - ), - SizedBox(height: 4.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - quickText('累计停顿:2次', color: Colors.white, size: 7.sp), - quickText('04:30', color: Colors.white, size: 7.sp), - ], - ) - ], - ), - ), - SizedBox(width: 16.w), - InkWell( - onTap: () {}, - child: Container( - // alignment: Alignment., - padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h), - decoration: BoxDecoration(color: Color.fromRGBO(182, 197, 250, 1), borderRadius: BorderRadius.circular(4.r)), - child: quickText('原速播放', color: Color.fromRGBO(79, 114, 244, 1), size: 10.sp, align: TextAlign.center), - ), - ), - ], - ), - ), - ), + $BottomPlaybar(_dataDetail.timeConsuming, _dataDetail.pauseCount), ], ); } @@ -213,7 +147,13 @@ class UseMainBoxState with CommonMixin { final ValueNotifier pageNum; final ValueNotifier pageCount; final ValueNotifier handwritingData; - final ValueNotifier imageKey; + final ValueNotifier handwritingDetail; + + final ValueNotifier playPause; // 播放暂停 + final ValueNotifier constantFastSpeed; // 原速、快速 默认原速 + + GlobalKey<_HandwritingDrawBoxState> handwritingKey; + UseMainBoxState._({ required this.jobId, required this.studentId, @@ -221,7 +161,10 @@ class UseMainBoxState with CommonMixin { required this.handwritingData, required this.questionNo, required this.pageCount, - required this.imageKey, + required this.playPause, + required this.constantFastSpeed, + required this.handwritingDetail, + required this.handwritingKey, }); // 工厂构造函数 @@ -232,8 +175,11 @@ class UseMainBoxState with CommonMixin { questionNo: questionNo, pageNum: useState(pageNum), handwritingData: useState(null), + handwritingDetail: useState(null), pageCount: useState(0), - imageKey: useState(null), + playPause: useState(false), + constantFastSpeed: useState(false), + handwritingKey: GlobalKey(), ); } @@ -244,12 +190,717 @@ class UseMainBoxState with CommonMixin { var res = await _client.getHandwriting(jobId, studentId, questionNo, pageNum.value); if (res?.success ?? false) { handwritingData.value = res!.data; + if (handwritingData.value!.lattices.isEmpty) { + Future.delayed(Duration.zero, () => ToastUtils.showInfo('此页试题没有笔迹')); + } return; } Future.delayed(Duration(seconds: 1), () => ToastUtils.showError(res?.message ?? '笔记数据请求失败')); } catch (e) { + print(e); } finally { ToastUtils.dismiss(); } } + + HandwritingInfo? getHandwritingDetail(JobHandwriting? theData) { + if (theData == null) return null; + print('开始时间:${DateTime.now().millisecondsSinceEpoch}'); + // 笔画分组 + // var lattices = Map>.fromIterable( + // theData.lattices, + // key: (key) => key.stroke, + // value: (value) { + // // return theData.lattices.where((item) => item.stroke == value.stroke).toList()..sort((a, b) => a.time.compareTo(b.time)); + // return theData.lattices.where((item) => item.stroke == value.stroke).toList(); + // }, + // ); + var lattices = Map>(); + var theLattices = theData.lattices; + for (var i = 0; i < theLattices.length; i++) { + Lattices item = theLattices[i]; + if (!lattices.containsKey(item.stroke)) lattices[item.stroke] = []; + lattices[item.stroke]!.add(item); // 添加笔画数据 + } + + print('分组时间:${DateTime.now().millisecondsSinceEpoch}'); + List latticeKeys = lattices.keys.toList(); + int timeConsuming = 0; + if (latticeKeys.isNotEmpty) { + List? firstAction = lattices[latticeKeys[0]]; + List? lastAction = lattices[latticeKeys[latticeKeys.length - 1]]; + int firstTime = 0; + int lastTime = 0; + + if (firstAction?.isNotEmpty ?? false) { + // 第一个笔画集合 + firstTime = firstAction![0].time; + } + if (lastAction?.isNotEmpty ?? false) { + // 最后一笔画集合 + lastTime = lastAction![0].time; + } + timeConsuming = lastTime - firstTime; + } + print('获取数据总时间:${DateTime.now().millisecondsSinceEpoch}'); + var pauseCount = 0; // 停顿次数 + for (var i = 0; i < latticeKeys.length; i++) { + var currentLattices = lattices[latticeKeys[i]]!; // 当前循环笔画集合 + var prevLattices = i == 0 ? null : lattices[latticeKeys[i - 1]]!; // 下一个笔画集合 + for (var j = 0; j < currentLattices.length; j++) { + var intervalTime = 0; + var lattice = currentLattices[j]; + + if (j != 0) { + var prevItem = currentLattices[j - 1]; + var adjacentSpacingTime = lattice.time - prevItem.time; + if (adjacentSpacingTime > 5000) { + // 大于5秒算一次停顿 + pauseCount++; + } + intervalTime = adjacentSpacingTime + prevItem.intervalTime; + } else { + if (i != 0 && prevLattices != null) { + var prevLatticeLastItem = prevLattices[prevLattices.length - 1]; + var adjacentSpacingTime = lattice.time - prevLatticeLastItem.time; + if (adjacentSpacingTime > 5000) { + // 大于5秒算一次停顿 + pauseCount++; + } + intervalTime = adjacentSpacingTime + prevLatticeLastItem.intervalTime; + } + } + lattice.intervalTime = intervalTime; + } + } + return HandwritingInfo(pauseCount, timeConsuming, lattices); + } +} + +class HandwritingInfo { + int pauseCount; // 停顿次数 + int timeConsuming; // 耗时(毫秒) + Map> strokeMap; // 笔画数据 + + HandwritingInfo(this.pauseCount, this.timeConsuming, this.strokeMap); +} + +// 图片展示 +@hwidget +Widget $theCachedNetworkImage(ImageWidgetBuilder imageBuilder, {required String imageUrl}) { + UseCachedImgRefresh _useImgRefsh = UseCachedImgRefresh.use(); + + return CachedNetworkImage( + key: _useImgRefsh.imageKey.value, + fit: BoxFit.contain, + imageUrl: imageUrl, + imageBuilder: imageBuilder, + placeholder: (context, url) => Center(child: SpinKitWaveSpinner(color: Theme.of(context).primaryColor, size: 50.r)), + errorWidget: (context, url, error) { + return GestureDetector( + onTap: () => (_useImgRefsh.imageKey.value = UniqueKey()), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset('assets/images/test_paper_loading_failed.png'), + quickText('加载失败,点击重试', color: Color.fromRGBO(148, 163, 182, 1), size: 12.sp), + ], + ), + ); + }, + ); +} + +/// 上一页 +@swidget +Widget $previousNutton(BuildContext context, int? pageNum, Function call) { + if (pageNum != null && pageNum > 1) + return Positioned( + left: 3.w, + child: FloatingActionButton( + heroTag: '点击前往上一题', + tooltip: '点击前往上一题', + focusColor: Theme.of(context).primaryColor, + backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1), + elevation: 6.r, + onPressed: () => easyThrottle('answer_handwriting_previous', () => call()), + child: Icon(Icons.arrow_back_ios, color: Colors.white, size: 22.sp), + ), + ); + + return SizedBox(); +} + +/// 下一页 +@swidget +Widget $nextPageButton(BuildContext context, int? pageNum, int totalNum, Function call) { + if (pageNum != null && pageNum < totalNum) + return Positioned( + right: 3.w, + child: FloatingActionButton( + heroTag: '点击前往下一题', + tooltip: '点击前往下一题', + elevation: 6.r, + backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1), + onPressed: () => easyThrottle('answer_handwriting_next', () => call()), + child: Icon(Icons.arrow_forward_ios, color: Colors.white, size: 22.sp), + ), + ); + + return SizedBox(); +} + +// 笔记还原主框 +class HandwritingDrawBox extends StatefulHookConsumerWidget { + final String image; + final HandwritingInfo handwritingData; + // final double boxWidth; + // final double boxHeight; + const HandwritingDrawBox(this.image, this.handwritingData, {super.key}); + + @override + ConsumerState createState() => _HandwritingDrawBoxState(); +} + +class _HandwritingDrawBoxState extends ConsumerState with EventBusMixin { + ImageStream? imageStream; // 图片监听数据 + TestQuestionsImageInfo? imagInfoModel; // 试题图片数据 + late ImageStreamListener theImageStreamListener; + + List> _packagedHandwritingDatas = []; + List _packagedHandwritingDataAll = []; + List pendingData = []; // 待执行数据 + List timers = []; + int handwritingTime = 0; + int handwritingDuration = 0; + @override + void initState() { + super.initState(); + + eventOn(callback: (e) { + switch (e.runtimeType) { + case JobHandwritingRunTimeBus: + var _model = (e as JobHandwritingRunTimeBus); + var _runtime = _model.runTimeVal; + handwritingDuration = _model.totalVal; + handwritingTime = _runtime; + if (_runtime <= 0) { + pendingData.clear(); + } + break; + case JobHandwritingDragProgressBarBus: + var _model = (e as JobHandwritingDragProgressBarBus); + dragProgressBarInitData(_model.changeVal, _model.totalVal); + break; + case JobHandwritingPlaybarBus: + // 播放 暂停 + var _val = e as JobHandwritingPlaybarBus; + if (_val.play) { + // 播放 + toGoPlay(); + } else { + // 暂停 + toGoPause(); + } + break; + default: + } + }); + + theImageStreamListener = ImageStreamListener((ImageInfo info, bool _) { + if (imagInfoModel != null) return; + imagInfoModel = TestQuestionsImageInfo( + // 获取图片的宽高 + boxHeight: ScreenUtil().scaleHeight, // 图片展示自适应所以 这里无法获取容器的高度 + boxWidth: ScreenUtil().screenWidth - 60.r, + url: widget.image, + height: info.image.height.toDouble(), + width: info.image.width.toDouble(), + )..calculateStartAndEndHeight(60.h); // 60.h是底部的播放栏高度 + getCalculatedSize(); + }); + } + + @override + void dispose() { + timers.forEach((e) { + if (e.isActive) e.cancel(); + }); + try { + imageStream?.removeListener(theImageStreamListener); + eventCancel(); + } catch (e) {} + super.dispose(); + } + + // 暂停播放 + Future toGoPause() async { + timers.forEach((e) { + if (e.isActive) e.cancel(); + }); + timers = []; + if (pendingData.isNotEmpty && handwritingTime > 0 && (handwritingDuration - handwritingTime > 0)) { + // 待执行的数据不等于空 每个数据都需要减去当前暂停已经执行的时间 + pendingData = pendingData.map((e) { + return GestureHandwritingRecording( + stroke: e.stroke, + data: e.data, + usageTime: e.usageTime, + intervalTime: e.intervalTime - (handwritingDuration - handwritingTime) * 1000, + ); + }).toList(); + } + } + + /// 拖动进度条后重新初始化数据 + /// @param startTime 起始时间 单位秒 + Future dragProgressBarInitData(int startTime, int totalDuration) async { + timers.forEach((e) { + if (e.isActive) e.cancel(); + }); + timers = []; + pendingData.clear(); + + if (startTime == 0) { + ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); + pendingData.addAll(_packagedHandwritingDataAll); + } else { + // 待执行的数据不等于空 每个数据都需要减去当前暂停已经执行的时间 + startTime = startTime * 1000; // 转为毫秒 + List executeImmediately = []; // 立即执行数据 + List waitingExecution = []; // 等待执行数据 + + for (var i = 0; i < _packagedHandwritingDataAll.length; i++) { + var item = _packagedHandwritingDataAll[i]; + + if (item.intervalTime <= startTime) { + // 需要直接装配到直接打印的容器 + executeImmediately.add(item); + } else { + // 需要等待的数据 + waitingExecution.add(GestureHandwritingRecording( + stroke: item.stroke, + data: item.data, + usageTime: item.usageTime, + intervalTime: item.intervalTime - startTime, + )); + } + } + + pendingData = waitingExecution; + ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal(executeImmediately); + eventFire(model: JobHandwritingPlaybarBus(true)); + } + } + + Future zhixinCall(GestureHandwritingRecording e) async { + if (mounted) { + List trajectorys = ref.read(jobHandwritingDrawingTrajectoryProvider)..add(e); + ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal(List.from(trajectorys)); + pendingData.remove(e); // 执行后删除容器中的当前动作 + } + } + + /// 开始播放 + Future toGoPlay() async { + handwritingTime = 0; + var executableData = _packagedHandwritingDataAll; + if (pendingData.isNotEmpty) { + // 待执行的数据没有执行完成 就继续执行待执行数据 + executableData = pendingData; + } else { + pendingData.addAll(_packagedHandwritingDataAll); + ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); + } + + executableData.forEach((e) { + if (e.intervalTime == 0) { + zhixinCall(e); + } else { + var ter = Timer(Duration(milliseconds: e.intervalTime), () => zhixinCall(e)); + timers.add(ter); + } + }); + } + + // 计算尺寸 + Future getCalculatedSize() async { + if (imagInfoModel == null) return; + var dataInfo = widget.handwritingData; + Map> mapData = dataInfo.strokeMap; + if (mapData.isNotEmpty) { + List keys = mapData.keys.toList(); + + for (var i = 0; i < keys.length; i++) { + List newTrajectoryData = mapData[keys[i]]!.map((e) { + double theX = e.x * imagInfoModel!.scale!; + double theY = e.y * imagInfoModel!.scale!; + + return GestureHandwritingRecording( + data: Offset(theX, theY), + usageTime: e.time.toInt(), + intervalTime: e.intervalTime, + stroke: e.stroke, + ); + }).toList(); + + _packagedHandwritingDatas.add(newTrajectoryData); // 分组数据 + _packagedHandwritingDataAll.addAll(newTrajectoryData); // 不分组数据 + } + Future.delayed(Duration.zero, () => eventFire(model: JobHandwritingGetReadyBus())); // 通知外部可以播放笔迹 + } + } + + @override + Widget build(BuildContext context) { + List points = ref.watch(jobHandwritingDrawingTrajectoryProvider); + return Container( + alignment: Alignment.center, + child: CustomPaint( + foregroundPainter: DrawingPainter(points: points), + // size: Size(ScreenUtil().screenWidth - 60.r, widget.boxHeight), + child: RepaintBoundary( + child: $TheCachedNetworkImage( + imageUrl: widget.image, + (context, imageProvider) { + Image imageWidget = Image(image: imageProvider, fit: BoxFit.contain); + if (imagInfoModel == null) { + imageStream?.removeListener(theImageStreamListener); + // 视图中展示图片的尺寸计算获取 + imageStream = imageWidget.image.resolve(ImageConfiguration()); + imageStream?.addListener(theImageStreamListener); + } + + return imageWidget; + }, + ), + ), + ), + ); + } +} + +class DrawingPainter extends CustomPainter { + List points; + + DrawingPainter({required this.points}) : super(); + + // Paint paintBrush = Paint() + // ..color = Colors.black + // ..strokeCap = StrokeCap.round + // ..strokeWidth = 0.5.sp; + + //[定义画笔] + final Paint paintBrush = Paint() + //画笔颜色 + ..color = Colors.black + //画笔笔触类型 + ..strokeCap = StrokeCap.round + //是否启动抗锯齿 + // ..isAntiAlias = true + //绘画风格,默认为填充 + // ..style = PaintingStyle.fill + //画笔的宽度 + ..strokeWidth = 0.6.r; + + @override + void paint(Canvas canvas, Size size) { + // canvas.drawPoints(PointMode.points, thePoints, paintBrush); + var _length = points.length; + for (int i = 0; i < _length; i++) { + GestureHandwritingRecording item = points[i]; + GestureHandwritingRecording? nextItem = i + 1 >= _length ? null : points[i + 1]; + Offset? offsetData = item.data; + + Offset? nextOffsetData = nextItem?.data; + if (nextOffsetData != null && item.stroke == nextItem?.stroke) { + canvas.drawLine(offsetData, nextOffsetData, paintBrush); + } + } + } + + @override + bool shouldRepaint(DrawingPainter oldDelegate) => true; +} + +@swidget +Widget $pageNumberBox(int pageNum) { + return Positioned( + top: 6.h, + right: 4.w, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h), + decoration: BoxDecoration( + color: Color.fromRGBO(0, 0, 0, 0.47), + borderRadius: BorderRadius.circular(5.r), + ), + child: quickText('第$pageNum页', color: Colors.white, size: 10.sp), + ), + ); +} + +@hwidget +Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { + var usePlaybar = UseBottomPlaybar.use(timeConsuming); + + useValueChanged(timeConsuming, (_, __) { + var seds = timeConsuming ~/ 1000; + if ((timeConsuming % 1000) > 500) seds += 1; + usePlaybar.handwritingDuration.value = seds; + }); + + useValueChanged(usePlaybar.handwritingDuration.value, (_, __) { + usePlaybar.useTime.value = usePlaybar.handwritingDuration.value; + }); + // 播放速度 + useValueChanged(usePlaybar.constantFastSpeed.value, (_, __) { + usePlaybar.eventFire(model: PlaybackSpeedBus(usePlaybar.constantFastSpeed.value.speed)); + }); + // 计时结束监听 + useValueChanged(usePlaybar.useTime.value, (_, __) { + var _runtime = usePlaybar.useTime.value; + if (_runtime <= 0 || usePlaybar.handwritingDuration.value == _runtime) { + Future.delayed(Duration.zero, () => (usePlaybar.playPause.value = false)); // 初始化播放按钮 + } + usePlaybar.eventFire(model: JobHandwritingRunTimeBus(_runtime, usePlaybar.handwritingDuration.value)); + }); + + useEffect(() { + usePlaybar.eventOn(callback: (e) { + // TODO 数据 + switch (e.runtimeType) { + case JobHandwritingPlaybarBus: + // 出发播放暂停 + var _val = e as JobHandwritingPlaybarBus; + if (_val.play) { + // 开始播放 + usePlaybar.playTimingStarts(); + if (!usePlaybar.playPause.value) { + usePlaybar.playPause.value = true; + } + } else { + // 暂停播放 + usePlaybar.playTimingSuspend(); + if (usePlaybar.playPause.value) { + usePlaybar.playPause.value = false; + } + } + break; + case JobHandwritingGetReadyBus: + // 作业笔迹已经计算好坐标 可以开始播放 + Future.delayed(Duration.zero, () => (usePlaybar.handWritingReady.value = true)); + break; + case PlaybackSpeedBus: + break; + default: + } + }); + + return () { + try { + usePlaybar.eventCancel(); + usePlaybar.timer.value?.cancel(); + } catch (e) { + print(e); + } + }; + }, []); + + return Container( + height: 60.h, + padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h), + alignment: Alignment.center, + color: Color.fromRGBO(0, 0, 0, 0.5), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (usePlaybar.handWritingReady.value) + InkWell( + onTap: () => easyThrottle('job_handwriting_play_pause', () { + usePlaybar.playPause.value = !usePlaybar.playPause.value; + usePlaybar.eventFire(model: JobHandwritingPlaybarBus(usePlaybar.playPause.value)); + }), + child: Icon( + !usePlaybar.playPause.value ? Icons.play_circle_outline : Icons.pause_circle_outline, + color: Colors.white, + size: 28.r, + ), + ) + else + SpinKitPouringHourGlassRefined(size: 40.sp, color: Colors.white), + SizedBox(width: 6.w), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + height: 20.h, + // color: Theme.of(context).primaryColor, + child: Slider( + /// 进度条的值 + value: (usePlaybar.handwritingDuration.value - usePlaybar.useTime.value).toDouble(), + + /// 进度条的最小值(默认为 0) + min: 0.0, + + /// 进度条的最大值(默认为 1) + max: usePlaybar.handwritingDuration.value.toDouble(), + // divisions:1, + + /// 滑块以及滑块左侧的颜色 + // activeColor: Colors.red, + + /// 滑块右侧的颜色 + inactiveColor: Color.fromRGBO(217, 217, 217, 1), + + /// 进度值发生变化时触发的事件(注:把 onChanged 设置为 null 则说明 Slider 为不可用状态) + onChangeEnd: (value) { + usePlaybar.playTimingSuspend(); // 暂停计时器得暂停 + usePlaybar.eventFire(model: JobHandwritingDragProgressBarBus(value.toInt(), usePlaybar.handwritingDuration.value)); + usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); + }, + onChanged: (double value) { + usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); + }, + ), + + // /// 手指按下滑块时触发的事件 + // onChangeStart: (value) => log('onChangeStart: $value'), + + // /// 手指从滑块抬起时触发的事件 + // onChangeEnd: (value) => log('onChangeEnd: $value'), + ), + SizedBox(height: 4.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + quickText('累计停顿:$pauseCount次', color: Colors.white, size: 7.sp), + quickText(convertSeconds(usePlaybar.useTime.value)?.toString() ?? '', color: Colors.white, size: 7.sp), + ], + ) + ], + ), + ), + SizedBox(width: 16.w), + InkWell( + onTap: () => easyThrottle('job_handwriting_speed', () { + var theIndex = PlaybackSpeed.values.indexOf(usePlaybar.constantFastSpeed.value); + if (theIndex == PlaybackSpeed.values.length - 1) { + theIndex = -1; + } + usePlaybar.constantFastSpeed.value = PlaybackSpeed.values[theIndex + 1]; + }), + child: Container( + // alignment: Alignment., + padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h), + decoration: BoxDecoration(color: Color.fromRGBO(182, 197, 250, 1), borderRadius: BorderRadius.circular(4.r)), + child: quickText( + '${usePlaybar.constantFastSpeed.value.name}', + color: Color.fromRGBO(79, 114, 244, 1), + size: 10.sp, + align: TextAlign.center, + ), + ), + ), + ], + ), + ); +} + +class UseBottomPlaybar with EventBusMixin { + final ValueNotifier handwritingDuration; // 笔迹总时长 + final ValueNotifier playPause; // 播放暂停 + final ValueNotifier constantFastSpeed; // 原速、快速 默认原速 + final ValueNotifier handWritingReady; + + final ValueNotifier useTime; // 耗时 单位:(秒) + + final ValueNotifier timer; + + UseBottomPlaybar._( + {required this.handWritingReady, + required this.handwritingDuration, + required this.playPause, + required this.constantFastSpeed, + required this.useTime, + required this.timer}); + + // 工厂构造函数 + factory UseBottomPlaybar.use(int milliseconds) { + int handwritingDuration = milliseconds ~/ 1000; + if ((milliseconds % 1000) > 500) handwritingDuration += 1; + return UseBottomPlaybar._( + playPause: useState(false), + constantFastSpeed: useState(PlaybackSpeed.ORIGINAL_SPEED), + useTime: useState(handwritingDuration), + timer: useState(null), + handwritingDuration: useState(handwritingDuration), + handWritingReady: useState(false), + ); + } + + /// 开始计时 + void playTimingStarts() { + if (useTime.value > 0) { + timer.value?.cancel(); + timer.value = Timer.periodic(Duration(seconds: 1), (theTime) { + useTime.value -= 1; + if (useTime.value < 0) { + timer.value?.cancel(); + timer.value = null; + useTime.value = handwritingDuration.value; + } + }); + } + } + + /// 暂停 + void playTimingSuspend() { + timer.value?.cancel(); + timer.value = null; + } +} + +// 播放按钮 +class JobHandwritingPlaybarBus { + bool play; + JobHandwritingPlaybarBus(this.play); +} + +// 笔迹是否已经准备好(笔迹计算好坐标后通知通知栏可以开始播放) +class JobHandwritingGetReadyBus { + JobHandwritingGetReadyBus(); +} + +// 笔记运行时间 +class JobHandwritingRunTimeBus { + int runTimeVal; + int totalVal; + JobHandwritingRunTimeBus(this.runTimeVal, this.totalVal); +} + +// 拖动进度条 +class JobHandwritingDragProgressBarBus { + int changeVal; + int totalVal; + JobHandwritingDragProgressBarBus(this.changeVal, this.totalVal); +} + +// 播放速度 (原速播放/快速播放) +class PlaybackSpeedBus { + double speed; + PlaybackSpeedBus(this.speed); +} + +// 播放倍速 +enum PlaybackSpeed { + ORIGINAL_SPEED(name: '原速播放', speed: 1), + ONE_POINT_FIVE_SPEED(name: '1.5x播放', speed: 1.5), + DOUBLE_SPEED(name: '2.0x播放', speed: 2), + TRIPLE_SPEED(name: '3.0x播放', speed: 3); + + const PlaybackSpeed({required this.name, required this.speed}); + final double speed; + final String name; } diff --git a/marking_app/lib/utils/my_time_util.dart b/marking_app/lib/utils/my_time_util.dart new file mode 100644 index 0000000..237cfbd --- /dev/null +++ b/marking_app/lib/utils/my_time_util.dart @@ -0,0 +1,65 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'my_time_util.g.dart'; + +// 毫秒转小时、分钟、秒的函数 +TimeUnitModel? convertMilliseconds(int milliseconds) { + try { + int hours = milliseconds ~/ (1000 * 60 * 60); + int minutes = (milliseconds % (1000 * 60 * 60)) ~/ (1000 * 60); + int seconds = (milliseconds % (1000 * 60)) ~/ 1000; + + if ((milliseconds % 1000) > 500) seconds += 1; + + return TimeUnitModel(hours, minutes, seconds); + } catch (e) { + print('时间转换报错'); + } + return null; +} + +// 毫秒转小时、分钟、秒的函数 +TimeUnitModel? convertSeconds(int totalSeconds) { + try { + int hours = totalSeconds ~/ 3600; // 整除3600得到小时数 + int remainingSeconds = totalSeconds % 3600; // 取模3600得到剩余的秒数 + int minutes = remainingSeconds ~/ 60; // 整除60得到分钟数 + int seconds = remainingSeconds % 60; // 取模60得到最终的秒数 + + return TimeUnitModel(hours, minutes, seconds); + } catch (e) { + print('时间转换报错'); + } + return null; +} + +@JsonSerializable() +class TimeUnitModel extends Object { + int hours; + int minutes; + int seconds; + TimeUnitModel(this.hours, this.minutes, this.seconds); + + factory TimeUnitModel.fromJson(Map srcJson) => _$TimeUnitModelFromJson(srcJson); + + Map toJson() => _$TimeUnitModelToJson(this); + + @override + String toString() { + var timeStr = ''; + if (hours > 0) { + timeStr += '${hours > 9 ? hours : '0' + hours.toString()} '; + } + if (minutes > 0) { + timeStr += '${minutes > 9 ? minutes : '0' + minutes.toString()}'; + } + + if (timeStr.length > 0) { + timeStr += ':${seconds > 9 ? seconds : '0' + seconds.toString()}'; + } else { + timeStr += '00:${seconds > 9 ? seconds : '0' + seconds.toString()}'; + } + + return timeStr; + } +} From 23bd9501ffbf5e141fb44cdf6e96ccfe95be24d9 Mon Sep 17 00:00:00 2001 From: machuanyu <840649825@qq.com> Date: Wed, 24 Apr 2024 16:43:08 +0800 Subject: [PATCH 22/28] =?UTF-8?q?bug=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- marking_app/assets/images/icon_back_green.png | Bin 0 -> 303 bytes .../answer_trajectory.dart | 2 -- .../answer_trajectory_job_detail.dart | 20 +++++++++++--- .../components/imgDialog.dart | 25 ++++++++++++++++++ .../job_knowledge_points.dart | 6 ++--- .../job_knowledge_points_detail.dart | 13 ++++++--- .../pages/homework_correction/job_report.dart | 6 +++-- .../quick_check_personal.dart | 2 +- .../widget/answer_trajectory_job.dart | 16 +++++++++-- .../widget/report_table.dart | 6 +++-- .../widget/student_zg_table.dart | 15 ++++++----- 11 files changed, 84 insertions(+), 27 deletions(-) create mode 100644 marking_app/assets/images/icon_back_green.png create mode 100644 marking_app/lib/pages/homework_correction/components/imgDialog.dart diff --git a/marking_app/assets/images/icon_back_green.png b/marking_app/assets/images/icon_back_green.png new file mode 100644 index 0000000000000000000000000000000000000000..3df3757fc00634d06f467ce833ea95771764721d GIT binary patch literal 303 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9E$svykh8Km+7D9BhG z0Y z&LwIq8zu?PVA$m_^+NLzwl9pGk~bK<0!}3E=GpdGcz@Bu|0SPJa!fmtI_*lst8IcOL- zQ?$WCwdIk;jO958S~f7q9%7s2@ml#+liVb$D<4w)1-g9&8gKR75#Y|4cGcwnl(~$- wH#s*zopr00>NWRR910 literal 0 HcmV?d00001 diff --git a/marking_app/lib/pages/homework_correction/answer_trajectory.dart b/marking_app/lib/pages/homework_correction/answer_trajectory.dart index cd25e60..492dc3d 100644 --- a/marking_app/lib/pages/homework_correction/answer_trajectory.dart +++ b/marking_app/lib/pages/homework_correction/answer_trajectory.dart @@ -58,7 +58,6 @@ class _AnswerTrajectoryState extends State }); getStudentGroups(); getWorkList(); - print(userInfo); }); } @@ -107,7 +106,6 @@ class _AnswerTrajectoryState extends State } jobList = arr; setState(() {}); - print('total=${res.data!.total}'); refreshController2.finishRefresh(); EasyLoading.dismiss(); } diff --git a/marking_app/lib/pages/homework_correction/answer_trajectory_job_detail.dart b/marking_app/lib/pages/homework_correction/answer_trajectory_job_detail.dart index 967160c..9d47897 100644 --- a/marking_app/lib/pages/homework_correction/answer_trajectory_job_detail.dart +++ b/marking_app/lib/pages/homework_correction/answer_trajectory_job_detail.dart @@ -185,8 +185,14 @@ class _AnswerTrajectoryJobDetailState extends State var item = students[index]; return InkWell( onTap: (){ - RouterManager.router.navigateTo(context, - '${RouterManager.jobPersonalDetailPath}?studentId=${item.studentId}&studentName=${Uri.encodeComponent(item.studentName)}'); + RouterManager.router.navigateTo( + context, + RouterManager.quickCheckPersonalPath + + '?jobId=${widget.jobId}&studentId=${item.studentId}', + transition: getTransition(), + ); + // RouterManager.router.navigateTo(context, + // '${RouterManager.jobPersonalDetailPath}?studentId=${item.studentId}&studentName=${Uri.encodeComponent(item.studentName)}'); }, child: Container( padding: EdgeInsets.symmetric(horizontal: 10.r), @@ -228,8 +234,14 @@ class _AnswerTrajectoryJobDetailState extends State var item = students[index]; return InkWell( onTap: (){ - RouterManager.router.navigateTo(context, - '${RouterManager.jobPersonalDetailPath}?studentId=${item.studentId}&studentName=${Uri.encodeComponent(item.studentName)}'); + RouterManager.router.navigateTo( + context, + RouterManager.quickCheckPersonalPath + + '?jobId=${widget.jobId}&studentId=${item.studentId}', + transition: getTransition(), + ); + // RouterManager.router.navigateTo(context, + // '${RouterManager.jobPersonalDetailPath}?studentId=${item.studentId}&studentName=${Uri.encodeComponent(item.studentName)}'); }, child: Container( padding: EdgeInsets.symmetric( diff --git a/marking_app/lib/pages/homework_correction/components/imgDialog.dart b/marking_app/lib/pages/homework_correction/components/imgDialog.dart new file mode 100644 index 0000000..50d9c09 --- /dev/null +++ b/marking_app/lib/pages/homework_correction/components/imgDialog.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class ImageDialog{ + static void showImgDialog(BuildContext context,String imgUrl) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + // insetPadding: EdgeInsets.symmetric(vertical: 10.r,horizontal: 45.r), + backgroundColor: Colors.transparent, + contentPadding: EdgeInsets.all(0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(15.r))), + content: Container( + width: MediaQuery.of(context).size.width - 48.r, + // height: MediaQuery.of(context).size.height * 0.4, + color: Colors.white, + // child: PhotoView(imageProvider: NetworkImage(imgUrl),backgroundDecoration: BoxDecoration(color: Colors.transparent),)), + child: Image.network(imgUrl)), + ); + }, + ); + } +} \ No newline at end of file diff --git a/marking_app/lib/pages/homework_correction/job_knowledge_points.dart b/marking_app/lib/pages/homework_correction/job_knowledge_points.dart index d114935..3c6e1b9 100644 --- a/marking_app/lib/pages/homework_correction/job_knowledge_points.dart +++ b/marking_app/lib/pages/homework_correction/job_knowledge_points.dart @@ -63,8 +63,8 @@ class _JobKnowledgePointsState extends State with CommonMixi } void getList() async { - print('startDataTime=$startDataTime'); - print('endDataTime=$endDataTime'); +/* print('startDataTime=$startDataTime'); + print('endDataTime=$endDataTime');*/ RestClient _client = await getClient(); BaseStructureResult> res = await _client.getKnowledgeReport(startDataTime,endDataTime,textController.text); @@ -265,7 +265,7 @@ class _JobKnowledgePointsState extends State with CommonMixi mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - '2次', + '${item.count}次', style: TextStyle(fontSize: 10.sp, color: Color(0xFF6888FD)), ), Image.asset('assets/images/right_icon_blue.png',width: 8.r,height: 8.r,), diff --git a/marking_app/lib/pages/homework_correction/job_knowledge_points_detail.dart b/marking_app/lib/pages/homework_correction/job_knowledge_points_detail.dart index f2f9611..96f1b64 100644 --- a/marking_app/lib/pages/homework_correction/job_knowledge_points_detail.dart +++ b/marking_app/lib/pages/homework_correction/job_knowledge_points_detail.dart @@ -271,7 +271,7 @@ class _JobKnowledgePointsDetailState extends State ), child: Center( child: Text( - '${item.questionNo}题', + '第${item.questionNo}题', style: TextStyle( fontSize: 10.sp, color: Color(0xFF8B8B8B)), @@ -307,10 +307,15 @@ class _JobKnowledgePointsDetailState extends State borderRadius: BorderRadius.circular(20.r), ), - child: Center( - child: quickText('正确率 >', + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + quickText('正确率', color: Color(0xFF4CC793), - size: 10.sp))), + size: 10.sp), + Image.asset('assets/images/icon_back_green.png',width: 8.r,height: 8.r,) + ], + )), ), Expanded( flex: 1, diff --git a/marking_app/lib/pages/homework_correction/job_report.dart b/marking_app/lib/pages/homework_correction/job_report.dart index 810008f..98b2730 100644 --- a/marking_app/lib/pages/homework_correction/job_report.dart +++ b/marking_app/lib/pages/homework_correction/job_report.dart @@ -9,6 +9,7 @@ import 'package:marking_app/common/model/job/job_report_join_class.dart'; import 'package:marking_app/common/model/job/job_report_knowledge_model.dart'; import 'package:marking_app/common/model/job/job_report_model.dart'; import 'package:marking_app/components/ReturnToHomepage.dart'; +import 'package:marking_app/pages/homework_correction/components/imgDialog.dart'; import 'package:marking_app/pages/homework_correction/widget/report_table.dart'; import 'package:marking_app/pages/homework_correction/widget/top_count.dart'; import 'package:marking_app/pages/mainPage.dart'; @@ -1445,7 +1446,7 @@ Widget $unitTimeAnsweringSituation(BuildContext context, int jobid, List with Co ), child: Center( child: Text( - '历史查询', + '历史作业', style: TextStyle(fontSize: 10.r, color: Color(0xFF2080F7)), ), ), diff --git a/marking_app/lib/pages/homework_correction/widget/answer_trajectory_job.dart b/marking_app/lib/pages/homework_correction/widget/answer_trajectory_job.dart index afc5cd9..aa19102 100644 --- a/marking_app/lib/pages/homework_correction/widget/answer_trajectory_job.dart +++ b/marking_app/lib/pages/homework_correction/widget/answer_trajectory_job.dart @@ -23,7 +23,7 @@ class AnswerTrajectoryJob extends StatelessWidget { crossAxisCount: 2, //横轴三个子widget mainAxisSpacing: 10.h, crossAxisSpacing: 6.w, - childAspectRatio: 2.5 //宽高比为1时,子widget + childAspectRatio: 2.4 //宽高比为1时,子widget ), children: List.generate(jobList.length, (index) { JobTaskItem item = jobList[index]; @@ -49,6 +49,7 @@ class AnswerTrajectoryJob extends StatelessWidget { ), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, children: [ // 顶部任务名称 Padding( @@ -103,7 +104,10 @@ class AnswerTrajectoryJob extends StatelessWidget { ], ), ), - +Padding( + padding: EdgeInsets.symmetric(horizontal: 6.r), + child: Text('时间:${item.createTime.substring(0,10)}',style: TextStyle(fontSize: 10.sp),), +), Container( padding: EdgeInsets.symmetric(vertical: 6.h), decoration: BoxDecoration( @@ -170,6 +174,7 @@ class AnswerTrajectoryJob extends StatelessWidget { ), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, children: [ // 顶部任务名称 Padding( @@ -225,6 +230,13 @@ class AnswerTrajectoryJob extends StatelessWidget { ], ), ), + SizedBox( + height: 5.r, + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 14.r), + child: Text('时间:${item.createTime.substring(0,10)}',style: TextStyle(fontSize: 10.sp),), + ), SizedBox( height: 10.r, ), diff --git a/marking_app/lib/pages/homework_correction/widget/report_table.dart b/marking_app/lib/pages/homework_correction/widget/report_table.dart index cab74d0..840893c 100644 --- a/marking_app/lib/pages/homework_correction/widget/report_table.dart +++ b/marking_app/lib/pages/homework_correction/widget/report_table.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; import 'package:marking_app/common/model/job/job_report_model.dart'; +import 'package:marking_app/pages/homework_correction/components/imgDialog.dart'; import 'package:marking_app/routes/RouterManager.dart'; import 'package:marking_app/utils/easy_refresh/MyEmptyWidget.dart'; import 'package:marking_app/utils/index.dart'; @@ -359,7 +360,7 @@ class _ReportTableState extends State { onTap: () { if (item.questionPicture == null) return ToastUtils.showInfo('当前试题没有原题'); - Navigator.push( + /* Navigator.push( context, MaterialPageRoute(builder: (_) { return Scaffold( @@ -369,7 +370,8 @@ class _ReportTableState extends State { NetworkImage(item.questionPicture!)), ); }), - ); + );*/ + ImageDialog.showImgDialog(context,item.questionPicture!); }, child: Text('原题', style: TextStyle( diff --git a/marking_app/lib/pages/homework_correction/widget/student_zg_table.dart b/marking_app/lib/pages/homework_correction/widget/student_zg_table.dart index 8156fba..58c283c 100644 --- a/marking_app/lib/pages/homework_correction/widget/student_zg_table.dart +++ b/marking_app/lib/pages/homework_correction/widget/student_zg_table.dart @@ -2,6 +2,7 @@ import 'package:data_table_2/data_table_2.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:marking_app/common/model/job/job_data_report.dart'; +import 'package:marking_app/pages/homework_correction/components/imgDialog.dart'; import 'package:marking_app/utils/common_utils.dart'; import 'package:marking_app/utils/easy_refresh/MyEmptyWidget.dart'; import 'package:photo_view/photo_view.dart'; @@ -29,22 +30,22 @@ class _StudentZgTableState extends State { int? _sortColumnIndex; bool _sortAscending = true; - void showImgDialog(BuildContext context,String imgUrl){ + /*void showImgDialog(BuildContext context,String imgUrl){ Navigator.push( context, MaterialPageRoute(builder: (_) { return Scaffold( appBar: AppBar(), body: SizedBox( - /* width: MediaQuery.of(context).size.width * 0.6, - height: MediaQuery.of(context).size.height * 0.6,*/ + *//* width: MediaQuery.of(context).size.width * 0.6, + height: MediaQuery.of(context).size.height * 0.6,*//* child: PhotoView( imageProvider: NetworkImage(imgUrl)), ), ); }), - ); + );*/ /* showDialog(context: context, builder: (BuildContext context){ return AlertDialog( // insetPadding: EdgeInsets.symmetric(vertical: 20.r,horizontal: 20.r), @@ -62,7 +63,7 @@ class _StudentZgTableState extends State { ), ); });*/ - } + // } DataRow _getRow(int index, [Color? color]) { assert(index >= 0); @@ -88,7 +89,7 @@ class _StudentZgTableState extends State { DataCell(InkWell( onTap: (){ if(item.state != 0){ - showImgDialog(context,item.studentAnswer!); + ImageDialog.showImgDialog(context,item.studentAnswer!); } }, @@ -111,7 +112,7 @@ class _StudentZgTableState extends State { DataCell(InkWell( onTap: (){ if(item.state==1 || item.state==2){ - showImgDialog(context,item.annotateAnswers!); + ImageDialog.showImgDialog(context,item.annotateAnswers!); } }, From 3a6e220f5e0526a98433c439f206586270f1c83b Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Wed, 24 Apr 2024 18:10:18 +0800 Subject: [PATCH 23/28] no message --- .../components/trajectoryView.dart | 43 ++-- .../homework_correction/do_papers_job.dart | 91 ++++---- .../quick_check_personal.dart | 11 +- .../widget/answer_handwriting.dart | 220 ++++++++++++------ .../widget/student_kg_table.dart | 69 +++--- .../widget/student_zg_table.dart | 102 ++++---- 6 files changed, 320 insertions(+), 216 deletions(-) diff --git a/marking_app/lib/pages/homework_correction/components/trajectoryView.dart b/marking_app/lib/pages/homework_correction/components/trajectoryView.dart index 534d798..0f6568a 100644 --- a/marking_app/lib/pages/homework_correction/components/trajectoryView.dart +++ b/marking_app/lib/pages/homework_correction/components/trajectoryView.dart @@ -21,12 +21,7 @@ class TrajectoryView extends StatefulHookConsumerWidget { final double boxHeight; final String questionNumber; final JobNoteTakingTrajectory trajectory; - const TrajectoryView( - {required this.trajectory, - required this.questionNumber, - required this.boxHeight, - required this.boxWidth, - super.key}); + const TrajectoryView({required this.trajectory, required this.questionNumber, required this.boxHeight, required this.boxWidth, super.key}); @override TrajectoryViewState createState() => TrajectoryViewState(); @@ -152,15 +147,11 @@ class TrajectoryViewState extends ConsumerState { /// 试题范围框左上角 trajectorys - ..add(GestureRecording( - data: Offset(2.w, trajectory.pictureQuestionTop), scopeBox: true, annotationSwitch: false, eraser: false)) + ..add(GestureRecording(data: Offset(2.w, trajectory.pictureQuestionTop), scopeBox: true, annotationSwitch: false, eraser: false)) /// 右上角 ..add(GestureRecording( - data: Offset(imagInfoModel!.scaleWidth! - 4.w, trajectory.pictureQuestionTop), - scopeBox: true, - annotationSwitch: false, - eraser: false)) + data: Offset(imagInfoModel!.scaleWidth! - 4.w, trajectory.pictureQuestionTop), scopeBox: true, annotationSwitch: false, eraser: false)) /// 左下角 ..add(GestureRecording( @@ -171,8 +162,7 @@ class TrajectoryViewState extends ConsumerState { /// 右下角 ..add(GestureRecording( - data: Offset( - imagInfoModel!.scaleWidth! - 4.w, trajectory.pictureQuestionTop + trajectory.pictureQuestionHeight), + data: Offset(imagInfoModel!.scaleWidth! - 4.w, trajectory.pictureQuestionTop + trajectory.pictureQuestionHeight), scopeBox: true, annotationSwitch: false, eraser: false)); @@ -181,12 +171,19 @@ class TrajectoryViewState extends ConsumerState { ref.read(jobDrawingTrajectoryProvider.notifier).setVal(trajectorys); }); if (lattices.isNotEmpty) { - Map> map = new Map.fromIterable(lattices, - key: (key) => key.stroke, - value: (value) { - return lattices.where((item) => item.stroke == value.stroke).toList() - ..sort((a, b) => a.time.compareTo(b.time)); - }); + // Map> map = new Map.fromIterable(lattices, + // key: (key) => key.stroke, + // value: (value) { + // return lattices.where((item) => item.stroke == value.stroke).toList() + // ..sort((a, b) => a.time.compareTo(b.time)); + // }); + + var map = Map>(); + for (var i = 0; i < lattices.length; i++) { + Lattices item = lattices[i]; + if (!map.containsKey(item.stroke)) map[item.stroke] = []; + map[item.stroke]!.add(item); // 添加笔画数据 + } List keys = map.keys.toList(); for (var i = 0; i < keys.length; i++) { @@ -199,8 +196,7 @@ class TrajectoryViewState extends ConsumerState { double theX = e.x * imagInfoModel!.scale!; double theY = e.y * imagInfoModel!.scale! + spacingHeight; - return GestureRecording( - eraser: false, data: Offset(theX, theY), usageTime: e.time.toInt(), annotationSwitch: false); + return GestureRecording(eraser: false, data: Offset(theX, theY), usageTime: e.time.toInt(), annotationSwitch: false); }).toList() ..add(GestureRecording(eraser: false, annotationSwitch: false)); // 原始轨迹展示 @@ -230,8 +226,7 @@ class TrajectoryViewState extends ConsumerState { if (duration2 == null && nextStrokesData != null) { // 此时最后一个笔画完成了 停止时间是在下一个笔画开始时间之差 Lattices minLattices = nextStrokesData.reduce((e1, e2) => e1.time < e2.time ? e1 : e2); - differenceInMilliseconds = - (Duration(milliseconds: minLattices.time.toInt()) - duration1).inMilliseconds; + differenceInMilliseconds = (Duration(milliseconds: minLattices.time.toInt()) - duration1).inMilliseconds; await Future.delayed(Duration(milliseconds: differenceInMilliseconds)); // 一个笔画完成进行下一个笔画的等待时间 } }; diff --git a/marking_app/lib/pages/homework_correction/do_papers_job.dart b/marking_app/lib/pages/homework_correction/do_papers_job.dart index 5710bcf..46b95c3 100644 --- a/marking_app/lib/pages/homework_correction/do_papers_job.dart +++ b/marking_app/lib/pages/homework_correction/do_papers_job.dart @@ -366,37 +366,55 @@ Widget $dropdownBoxSwitchStudentsOrTypeView(BuildContext context, {required Func Expanded(flex: 1, child: SizedBox()), Expanded( flex: 4, - child: Container( - padding: EdgeInsets.only(left: 10.w), - decoration: BoxDecoration( - color: Color.fromRGBO(244, 244, 244, 1), - borderRadius: BorderRadius.circular(4.r), - ), - child: DropdownButton( - onTap: () { - // 打开的时候请求刷新学生 - _useSwitchStudentAndType.getDataForStudents(taskId: taskId); - }, - padding: EdgeInsets.only(right: 4.w), - icon: Icon(Icons.keyboard_arrow_down_rounded), - value: _useSwitchStudentAndType.currentStudent.value?.studentId, - underline: Container(), - isExpanded: true, - items: _useSwitchStudentAndType.studentData.value.map((e) { - return DropdownMenuItem( - child: quickText(e.studentName, color: Color.fromRGBO(79, 79, 79, 1), size: 14.sp), - value: e.studentId, - ); - }).toList(), - hint: Text('请选择学生'), // 锚点的显示文本 - onChanged: (value) { - JobConcernedWithStudent? currentStudent = _useSwitchStudentAndType.currentStudent.value; - if (currentStudent?.studentId == value) return; - _useSwitchStudentAndType.studentBusInfo.value = null; // 置空BUS通知记录 - _useSwitchStudentAndType.currentStudent.value = - _useSwitchStudentAndType.studentData.value.firstWhereOrNull((element) => element.studentId == value); - }, - ), + child: Stack( + children: [ + Container( + padding: EdgeInsets.only(left: 10.w), + decoration: BoxDecoration( + color: Color.fromRGBO(244, 244, 244, 1), + borderRadius: BorderRadius.circular(4.r), + ), + child: DropdownButton( + onTap: () { + // 打开的时候请求刷新学生 + _useSwitchStudentAndType.getDataForStudents(taskId: taskId); + }, + padding: EdgeInsets.only(right: 4.w), + icon: Icon(Icons.keyboard_arrow_down_rounded), + value: _useSwitchStudentAndType.currentStudent.value?.studentId, + underline: Container(), + isExpanded: true, + items: _useSwitchStudentAndType.studentData.value.map((e) { + return DropdownMenuItem( + child: quickText(e.studentName, color: Color.fromRGBO(79, 79, 79, 1), size: 14.sp), + value: e.studentId, + ); + }).toList(), + hint: Text('请选择学生'), // 锚点的显示文本 + onChanged: (value) { + JobConcernedWithStudent? currentStudent = _useSwitchStudentAndType.currentStudent.value; + if (currentStudent?.studentId == value) return; + _useSwitchStudentAndType.studentBusInfo.value = null; // 置空BUS通知记录 + _useSwitchStudentAndType.currentStudent.value = + _useSwitchStudentAndType.studentData.value.firstWhereOrNull((element) => element.studentId == value); + }, + ), + ), + Positioned( + left: 2.w, + child: Stack( + alignment: const FractionalOffset(0.52, 0.24), + children: [ + Icon( + const IconData(0xe63d, fontFamily: "AlibabaIcon"), + size: 12.sp, + color: _useSwitchStudentAndType.isFirst.value ? Color.fromRGBO(76, 199, 147, 1) : Color.fromRGBO(164, 164, 164, 1), + ), + quickText('优先', size: 4.sp, color: Colors.white), + ], + ), + ), + ], ), ), Expanded(flex: 1, child: SizedBox()), @@ -458,17 +476,6 @@ Widget $dropdownBoxSwitchStudentsOrTypeView(BuildContext context, {required Func ), ), ), - Stack( - alignment: const FractionalOffset(0.52, 0.24), - children: [ - Icon( - const IconData(0xe63d, fontFamily: "AlibabaIcon"), - size: 12.sp, - color: _useSwitchStudentAndType.isFirst.value ? Color.fromRGBO(76, 199, 147, 1) : Color.fromRGBO(164, 164, 164, 1), - ), - quickText('优先', size: 4.sp, color: Colors.white), - ], - ), ], ), ), diff --git a/marking_app/lib/pages/homework_correction/quick_check_personal.dart b/marking_app/lib/pages/homework_correction/quick_check_personal.dart index 6021687..426618c 100644 --- a/marking_app/lib/pages/homework_correction/quick_check_personal.dart +++ b/marking_app/lib/pages/homework_correction/quick_check_personal.dart @@ -9,7 +9,6 @@ import 'package:marking_app/components/ReturnToHomepage.dart'; import 'package:marking_app/pages/homework_correction/widget/student_kg_table.dart'; import 'package:marking_app/pages/homework_correction/widget/student_zg_table.dart'; import 'package:marking_app/routes/RouterManager.dart'; -import 'package:marking_app/utils/common_utils.dart'; import 'package:marking_app/utils/request/rest_client.dart'; import 'package:marking_app/utils/toast_utils.dart'; @@ -179,6 +178,11 @@ class _QuickCheckPersonalState extends ConsumerState with Co child: StudentKgTable( headList: ['题号', '学生答案', '标准答案'], bodyList: studentInfo!.kgDetails, + questionNumCall: (no) { + showAnswerHandwriting(context, jobId: widget.jobId, studentId: widget.studentId, questionNo: int.parse(no)).then((value) { + ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); + }); + }, ), ) ], @@ -222,6 +226,11 @@ class _QuickCheckPersonalState extends ConsumerState with Co child: StudentZgTable( headList: ['题号', '用时', '学生答案', '批注结果', '批注'], bodyList: studentInfo!.zgDetails, + questionNumCall: (no) { + showAnswerHandwriting(context, jobId: widget.jobId, studentId: widget.studentId, questionNo: int.parse(no)).then((value) { + ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); + }); + }, ), ) ], diff --git a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart index bb5591a..b31d7dc 100644 --- a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart +++ b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:json_annotation/json_annotation.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -48,13 +49,14 @@ class AnswerHandwriting extends Dialog { } } -Future showAnswerHandwriting(BuildContext context, {required int jobId, required int studentId, int? pageNum}) async { +Future showAnswerHandwriting(BuildContext context, {required int jobId, required int studentId, int? pageNum, int? questionNo}) async { return showDialog( context: context, builder: (BuildContext context) => AnswerHandwriting( jobId: jobId, studentId: studentId, pageNum: pageNum, + questionNo: questionNo, closeCall: () => Navigator.of(context).pop(), ), ); @@ -94,7 +96,10 @@ class AnswerHandwritingMainBox extends HookWidget { }); useValueChanged(_useStateModel.pageNum.value, (oldVal, __) { - if (oldVal != null && oldVal != _useStateModel.pageNum.value) _useStateModel.getData().catchError((e) => closeCall()); + if (oldVal != null && oldVal != _useStateModel.pageNum.value) { + _useStateModel.questionNo = null; + _useStateModel.getData().catchError((e) => closeCall()); + } }); useEffect(() { @@ -106,7 +111,6 @@ class AnswerHandwritingMainBox extends HookWidget { HandwritingInfo? _dataDetail = _useStateModel.handwritingDetail.value; if (_data == null || _dataDetail == null) return Container(); - print('数据长度:${_data.lattices.length}'); return Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, @@ -134,7 +138,7 @@ class AnswerHandwritingMainBox extends HookWidget { ), ], ), - $BottomPlaybar(_dataDetail.timeConsuming, _dataDetail.pauseCount), + $BottomPlaybar(_dataDetail.timeConsuming, _dataDetail.pauseCount, _dataDetail.pauseInterval), ], ); } @@ -143,7 +147,7 @@ class AnswerHandwritingMainBox extends HookWidget { class UseMainBoxState with CommonMixin { final int jobId; final int studentId; - final int? questionNo; + int? questionNo; final ValueNotifier pageNum; final ValueNotifier pageCount; final ValueNotifier handwritingData; @@ -223,7 +227,6 @@ class UseMainBoxState with CommonMixin { lattices[item.stroke]!.add(item); // 添加笔画数据 } - print('分组时间:${DateTime.now().millisecondsSinceEpoch}'); List latticeKeys = lattices.keys.toList(); int timeConsuming = 0; if (latticeKeys.isNotEmpty) { @@ -242,8 +245,8 @@ class UseMainBoxState with CommonMixin { } timeConsuming = lastTime - firstTime; } - print('获取数据总时间:${DateTime.now().millisecondsSinceEpoch}'); var pauseCount = 0; // 停顿次数 + List pauseInterval = []; for (var i = 0; i < latticeKeys.length; i++) { var currentLattices = lattices[latticeKeys[i]]!; // 当前循环笔画集合 var prevLattices = i == 0 ? null : lattices[latticeKeys[i - 1]]!; // 下一个笔画集合 @@ -254,35 +257,38 @@ class UseMainBoxState with CommonMixin { if (j != 0) { var prevItem = currentLattices[j - 1]; var adjacentSpacingTime = lattice.time - prevItem.time; + intervalTime = adjacentSpacingTime + prevItem.intervalTime; if (adjacentSpacingTime > 5000) { // 大于5秒算一次停顿 pauseCount++; + pauseInterval.add(PauseIntervalTime(startTime: prevItem.intervalTime, endTime: intervalTime)); } - intervalTime = adjacentSpacingTime + prevItem.intervalTime; } else { if (i != 0 && prevLattices != null) { var prevLatticeLastItem = prevLattices[prevLattices.length - 1]; var adjacentSpacingTime = lattice.time - prevLatticeLastItem.time; + intervalTime = adjacentSpacingTime + prevLatticeLastItem.intervalTime; if (adjacentSpacingTime > 5000) { // 大于5秒算一次停顿 pauseCount++; + pauseInterval.add(PauseIntervalTime(startTime: prevLatticeLastItem.intervalTime, endTime: intervalTime)); } - intervalTime = adjacentSpacingTime + prevLatticeLastItem.intervalTime; } } lattice.intervalTime = intervalTime; } } - return HandwritingInfo(pauseCount, timeConsuming, lattices); + return HandwritingInfo(pauseCount, timeConsuming, lattices, pauseInterval); } } class HandwritingInfo { int pauseCount; // 停顿次数 + List pauseInterval; int timeConsuming; // 耗时(毫秒) Map> strokeMap; // 笔画数据 - HandwritingInfo(this.pauseCount, this.timeConsuming, this.strokeMap); + HandwritingInfo(this.pauseCount, this.timeConsuming, this.strokeMap, this.pauseInterval); } // 图片展示 @@ -374,6 +380,7 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev List timers = []; int handwritingTime = 0; int handwritingDuration = 0; + double speed = 1; // 播放速度 @override void initState() { super.initState(); @@ -404,6 +411,13 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev toGoPause(); } break; + case PlaybackSpeedBus: + // 播放速度 + var _model = (e as PlaybackSpeedBus); + speed = _model.speed; + toGoPause(); // 先暂停再重新播放 + toGoPlay(); // 重新播放 + break; default: } }); @@ -456,6 +470,7 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev /// 拖动进度条后重新初始化数据 /// @param startTime 起始时间 单位秒 Future dragProgressBarInitData(int startTime, int totalDuration) async { + eventFire(model: JobHandwritingPlaybarBus(false)); timers.forEach((e) { if (e.isActive) e.cancel(); }); @@ -474,16 +489,17 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev for (var i = 0; i < _packagedHandwritingDataAll.length; i++) { var item = _packagedHandwritingDataAll[i]; - if (item.intervalTime <= startTime) { + if (item.intervalTime < startTime) { // 需要直接装配到直接打印的容器 executeImmediately.add(item); } else { + var intervalTime = item.intervalTime - startTime; // 需要等待的数据 waitingExecution.add(GestureHandwritingRecording( stroke: item.stroke, data: item.data, usageTime: item.usageTime, - intervalTime: item.intervalTime - startTime, + intervalTime: intervalTime < 0 ? 0 : intervalTime, )); } } @@ -518,7 +534,7 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev if (e.intervalTime == 0) { zhixinCall(e); } else { - var ter = Timer(Duration(milliseconds: e.intervalTime), () => zhixinCall(e)); + var ter = Timer(Duration(milliseconds: e.intervalTime ~/ speed), () => zhixinCall(e)); timers.add(ter); } }); @@ -641,7 +657,7 @@ Widget $pageNumberBox(int pageNum) { } @hwidget -Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { +Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, List pauseIntervals) { var usePlaybar = UseBottomPlaybar.use(timeConsuming); useValueChanged(timeConsuming, (_, __) { @@ -656,6 +672,9 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { // 播放速度 useValueChanged(usePlaybar.constantFastSpeed.value, (_, __) { usePlaybar.eventFire(model: PlaybackSpeedBus(usePlaybar.constantFastSpeed.value.speed)); + // 播放速度变化 + usePlaybar.playTimingSuspend(); + usePlaybar.playTimingStarts(); }); // 计时结束监听 useValueChanged(usePlaybar.useTime.value, (_, __) { @@ -668,7 +687,6 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { useEffect(() { usePlaybar.eventOn(callback: (e) { - // TODO 数据 switch (e.runtimeType) { case JobHandwritingPlaybarBus: // 出发播放暂停 @@ -676,23 +694,17 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { if (_val.play) { // 开始播放 usePlaybar.playTimingStarts(); - if (!usePlaybar.playPause.value) { - usePlaybar.playPause.value = true; - } + if (!usePlaybar.playPause.value) usePlaybar.playPause.value = true; } else { // 暂停播放 usePlaybar.playTimingSuspend(); - if (usePlaybar.playPause.value) { - usePlaybar.playPause.value = false; - } + if (usePlaybar.playPause.value) usePlaybar.playPause.value = false; } break; case JobHandwritingGetReadyBus: // 作业笔迹已经计算好坐标 可以开始播放 Future.delayed(Duration.zero, () => (usePlaybar.handWritingReady.value = true)); break; - case PlaybackSpeedBus: - break; default: } }); @@ -711,7 +723,7 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { height: 60.h, padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h), alignment: Alignment.center, - color: Color.fromRGBO(0, 0, 0, 0.5), + color: Color.fromRGBO(0, 0, 0, 0.4), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ @@ -731,55 +743,92 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { SpinKitPouringHourGlassRefined(size: 40.sp, color: Colors.white), SizedBox(width: 6.w), Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - height: 20.h, - // color: Theme.of(context).primaryColor, - child: Slider( - /// 进度条的值 - value: (usePlaybar.handwritingDuration.value - usePlaybar.useTime.value).toDouble(), + child: LayoutBuilder( + builder: (context, constraints) { + final double containerWidth = constraints.maxWidth; // 展示区域总宽度 + // print('总刻度:$timeConsuming,宽度:$containerWidth'); + // print('总时长:${pauseIntervals.map((e) => e.toJson()).toList()}'); + var unitScale = containerWidth / timeConsuming; // 单位刻度 + var pauseIntervalsLength = pauseIntervals.length; + List pauseTickMarks = pauseIntervals.asMap().keys.map((e) { + bool isLast = e == pauseIntervalsLength - 1; + bool isFirst = e == 0; + var item = pauseIntervals[e]; + return Positioned( + top: 0, + left: unitScale * item.startTime, + child: Container( + width: unitScale * (item.apart ?? 0), + height: 8.h, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: isFirst + ? BorderRadius.only(topLeft: Radius.circular(8.r), bottomLeft: Radius.circular(10.r)) + : (isLast ? BorderRadius.only(topRight: Radius.circular(8.r), bottomRight: Radius.circular(10.r)) : null), + ), + ), + ); + }).toList(); - /// 进度条的最小值(默认为 0) - min: 0.0, - - /// 进度条的最大值(默认为 1) - max: usePlaybar.handwritingDuration.value.toDouble(), - // divisions:1, - - /// 滑块以及滑块左侧的颜色 - // activeColor: Colors.red, - - /// 滑块右侧的颜色 - inactiveColor: Color.fromRGBO(217, 217, 217, 1), - - /// 进度值发生变化时触发的事件(注:把 onChanged 设置为 null 则说明 Slider 为不可用状态) - onChangeEnd: (value) { - usePlaybar.playTimingSuspend(); // 暂停计时器得暂停 - usePlaybar.eventFire(model: JobHandwritingDragProgressBarBus(value.toInt(), usePlaybar.handwritingDuration.value)); - usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); - }, - onChanged: (double value) { - usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); - }, - ), - - // /// 手指按下滑块时触发的事件 - // onChangeStart: (value) => log('onChangeStart: $value'), - - // /// 手指从滑块抬起时触发的事件 - // onChangeEnd: (value) => log('onChangeEnd: $value'), - ), - SizedBox(height: 4.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + return Column( + mainAxisSize: MainAxisSize.min, children: [ - quickText('累计停顿:$pauseCount次', color: Colors.white, size: 7.sp), - quickText(convertSeconds(usePlaybar.useTime.value)?.toString() ?? '', color: Colors.white, size: 7.sp), + Stack( + children: [ + Container( + height: 8.h, + width: containerWidth, + decoration: BoxDecoration( + // color: Color.fromRGBO(146, 146, 146, 1), + color: Color.fromRGBO(202, 201, 201, 1), + borderRadius: BorderRadius.circular(50.r), + ), + ), + ...pauseTickMarks, + Container( + height: 8.h, + // color: Theme.of(context).primaryColor, + child: SliderTheme( + data: SliderTheme.of(context).copyWith( + trackHeight: 8.h, // 轨道高度 + trackShape: RoundedRectSliderTrackShape(), // 轨道形状,可以自定义 + activeTrackColor: Theme.of(context).primaryColor, // 激活的轨道颜色 + inactiveTrackColor: Colors.transparent, // 未激活的轨道颜色 + thumbShape: RoundSliderThumbShape(enabledThumbRadius: 0, disabledThumbRadius: 0), + thumbColor: Colors.white, // 滑块颜色 + overlayShape: RoundSliderOverlayShape(overlayRadius: 0), + overlayColor: Colors.black54, // 滑块外圈颜色 + // valueIndicatorShape: PaddleSliderValueIndicatorShape(), // 标签形状,可以自定义 + ), + child: Slider( + value: (usePlaybar.handwritingDuration.value - usePlaybar.useTime.value).toDouble(), + min: 0.0, + max: usePlaybar.handwritingDuration.value.toDouble(), + inactiveColor: Colors.transparent, + onChangeEnd: (value) { + usePlaybar.playTimingSuspend(); // 暂停计时器得暂停 + usePlaybar.eventFire(model: JobHandwritingDragProgressBarBus(value.toInt(), usePlaybar.handwritingDuration.value)); + usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); + }, + onChanged: (double value) { + usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); + }, + ), + ), + ), + ], + ), + SizedBox(height: 4.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + quickText('累计停顿:$pauseCount次', color: Colors.white, size: 7.sp), + quickText(convertSeconds(usePlaybar.useTime.value)?.toString() ?? '', color: Colors.white, size: 7.sp), + ], + ) ], - ) - ], + ); + }, ), ), SizedBox(width: 16.w), @@ -798,7 +847,7 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { child: quickText( '${usePlaybar.constantFastSpeed.value.name}', color: Color.fromRGBO(79, 114, 244, 1), - size: 10.sp, + size: 8.sp, align: TextAlign.center, ), ), @@ -808,6 +857,11 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount) { ); } +@swidget +Widget $pauseTickMark() { + return Container(); +} + class UseBottomPlaybar with EventBusMixin { final ValueNotifier handwritingDuration; // 笔迹总时长 final ValueNotifier playPause; // 播放暂停 @@ -844,7 +898,8 @@ class UseBottomPlaybar with EventBusMixin { void playTimingStarts() { if (useTime.value > 0) { timer.value?.cancel(); - timer.value = Timer.periodic(Duration(seconds: 1), (theTime) { + + timer.value = Timer.periodic(Duration(milliseconds: 1000 ~/ constantFastSpeed.value.speed), (theTime) { useTime.value -= 1; if (useTime.value < 0) { timer.value?.cancel(); @@ -898,9 +953,26 @@ enum PlaybackSpeed { ORIGINAL_SPEED(name: '原速播放', speed: 1), ONE_POINT_FIVE_SPEED(name: '1.5x播放', speed: 1.5), DOUBLE_SPEED(name: '2.0x播放', speed: 2), - TRIPLE_SPEED(name: '3.0x播放', speed: 3); + TRIPLE_SPEED(name: '3.0x播放', speed: 3), + FOUR_SPEED(name: '4.0x播放', speed: 4), + FIVE_SPEED(name: '5.0x播放', speed: 5), + SIX_SPEED(name: '6.0x播放', speed: 6); const PlaybackSpeed({required this.name, required this.speed}); final double speed; final String name; } + +@JsonSerializable() +class PauseIntervalTime extends Object { + int? apart; + int startTime; + int endTime; + PauseIntervalTime({required this.startTime, required this.endTime}) { + apart = endTime - startTime; + } + + factory PauseIntervalTime.fromJson(Map srcJson) => _$PauseIntervalTimeFromJson(srcJson); + + Map toJson() => _$PauseIntervalTimeToJson(this); +} diff --git a/marking_app/lib/pages/homework_correction/widget/student_kg_table.dart b/marking_app/lib/pages/homework_correction/widget/student_kg_table.dart index 7b622af..126455f 100644 --- a/marking_app/lib/pages/homework_correction/widget/student_kg_table.dart +++ b/marking_app/lib/pages/homework_correction/widget/student_kg_table.dart @@ -8,6 +8,7 @@ class StudentKgTable extends StatefulWidget { final List bodyList; final int? fixedRows; final int? fixedCols; + final Function(String)? questionNumCall; const StudentKgTable({ Key? key, @@ -15,6 +16,7 @@ class StudentKgTable extends StatefulWidget { required this.bodyList, this.fixedCols = 0, this.fixedRows = 0, + this.questionNumCall, }) : super(key: key); @override @@ -29,34 +31,51 @@ class _StudentKgTableState extends State { String sortString(String str) { return String.fromCharCodes(str.codeUnits.toList()..sort()); } + DataRow _getRow(int index, [Color? color]) { assert(index >= 0); KgDetails item = widget.bodyList[index]; return DataRow2.byIndex( index: index, - color: color != null ? MaterialStateProperty.all(color): null, + color: color != null ? MaterialStateProperty.all(color) : null, cells: [ - DataCell(Center( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(item.questionNo, - style: TextStyle(fontSize: 12.sp, color: Color(0xFF6888FD))), + DataCell( + InkWell( + onTap: () { + if (widget.questionNumCall != null) { + widget.questionNumCall!(item.questionNo); + } + }, + child: Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text(item.questionNo, style: TextStyle(fontSize: 12.sp, color: Color(0xFF6888FD))), + ), + ), ), - )), + ), DataCell(Center( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(item.studentAnswer == null?'未作答':item.studentAnswer!, - style: TextStyle(fontSize: 12.sp, color: item.studentAnswer == null?Color(0xFF525252): - item.state == 2?Color(0xFF4CC793): - item.state == 1?Color(0xFFFF7474):item.state == 0?Color(0xFFD3D3D3):Colors.white), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text( + item.studentAnswer == null ? '未作答' : item.studentAnswer!, + style: TextStyle( + fontSize: 12.sp, + color: item.studentAnswer == null + ? Color(0xFF525252) + : item.state == 2 + ? Color(0xFF4CC793) + : item.state == 1 + ? Color(0xFFFF7474) + : item.state == 0 + ? Color(0xFFD3D3D3) + : Colors.white), ), ))), DataCell(Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(item.questionAnswer == null ?'无':item.questionAnswer!, - style: TextStyle(fontSize: 12.sp, color: Color(0xFF525252))), + child: Text(item.questionAnswer == null ? '无' : item.questionAnswer!, style: TextStyle(fontSize: 12.sp, color: Color(0xFF525252))), ), )), ], @@ -74,14 +93,10 @@ class _StudentKgTableState extends State { dataRowHeight: 40.r, headingRowHeight: 40.r, border: TableBorder( - horizontalInside: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid), - bottom: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid), - verticalInside: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid)), - headingRowColor: MaterialStateProperty.resolveWith((states) => - widget.fixedCols! > 0 ? Colors.white : Colors.transparent), + horizontalInside: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid), + bottom: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid), + verticalInside: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid)), + headingRowColor: MaterialStateProperty.resolveWith((states) => widget.fixedCols! > 0 ? Colors.white : Colors.transparent), headingRowDecoration: BoxDecoration(color: Color(0xFFE6E6E6)), fixedColumnsColor: Color(0xFFE6E6E6), fixedCornerColor: Colors.grey[400], @@ -95,14 +110,12 @@ class _StudentKgTableState extends State { var item = widget.headList[index]; return DataColumn2( label: Center( - child: Text(item, - style: TextStyle(fontSize: 12.sp, color: Color(0xFF505767))), + child: Text(item, style: TextStyle(fontSize: 12.sp, color: Color(0xFF505767))), ), // size: ColumnSize.S, - fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r)/3, + fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r) / 3, ); }), - rows: List.generate(widget.bodyList.length, - (index) => _getRow(index, Color(0xFFF5F5F5)))); + rows: List.generate(widget.bodyList.length, (index) => _getRow(index, Color(0xFFF5F5F5)))); } } diff --git a/marking_app/lib/pages/homework_correction/widget/student_zg_table.dart b/marking_app/lib/pages/homework_correction/widget/student_zg_table.dart index 58c283c..232284d 100644 --- a/marking_app/lib/pages/homework_correction/widget/student_zg_table.dart +++ b/marking_app/lib/pages/homework_correction/widget/student_zg_table.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:marking_app/common/model/job/job_data_report.dart'; import 'package:marking_app/pages/homework_correction/components/imgDialog.dart'; +import 'package:marking_app/pages/homework_correction/widget/answer_handwriting.dart'; import 'package:marking_app/utils/common_utils.dart'; import 'package:marking_app/utils/easy_refresh/MyEmptyWidget.dart'; import 'package:photo_view/photo_view.dart'; @@ -12,6 +13,7 @@ class StudentZgTable extends StatefulWidget { final List bodyList; final int? fixedRows; final int? fixedCols; + final Function(String)? questionNumCall; const StudentZgTable({ Key? key, @@ -19,6 +21,7 @@ class StudentZgTable extends StatefulWidget { required this.bodyList, this.fixedCols = 0, this.fixedRows = 0, + this.questionNumCall, }) : super(key: key); @override @@ -29,7 +32,7 @@ class _StudentZgTableState extends State { final ScrollController _controller = ScrollController(); int? _sortColumnIndex; bool _sortAscending = true; - + /*void showImgDialog(BuildContext context,String imgUrl){ Navigator.push( context, @@ -37,8 +40,8 @@ class _StudentZgTableState extends State { return Scaffold( appBar: AppBar(), body: SizedBox( - *//* width: MediaQuery.of(context).size.width * 0.6, - height: MediaQuery.of(context).size.height * 0.6,*//* + */ /* width: MediaQuery.of(context).size.width * 0.6, + height: MediaQuery.of(context).size.height * 0.6,*/ /* child: PhotoView( imageProvider: NetworkImage(imgUrl)), @@ -70,57 +73,68 @@ class _StudentZgTableState extends State { KgDetails item = widget.bodyList[index]; return DataRow2.byIndex( index: index, - color: color != null ? MaterialStateProperty.all(color): null, + color: color != null ? MaterialStateProperty.all(color) : null, cells: [ - DataCell(Center( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(item.questionNo, - style: TextStyle(fontSize: 12.sp, color: Color(0xFF6888FD))), - ), - )), - DataCell(Center( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(CommonUtils.second2HMS(item.useTime!), - style: TextStyle(fontSize: 12.sp, color: Color(0xFF525252))), - ), - )), DataCell(InkWell( - onTap: (){ - if(item.state != 0){ - ImageDialog.showImgDialog(context,item.studentAnswer!); - } - + onTap: () { + if (widget.questionNumCall != null) { + widget.questionNumCall!(item.questionNo); + } }, child: Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(item.state!=0 ?'查看':'--', - style: TextStyle(fontSize: 12.sp, color: Color(0xFF3661FE))), + child: Text(item.questionNo, style: TextStyle(fontSize: 12.sp, color: Color(0xFF6888FD))), ), ), )), DataCell(Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 5.r), - child: item.state == 2? - Image.asset('assets/images/job_personal_correct_icon.png',width: 18.r,height: 18.r,):item.state == 1? - Image.asset('assets/images/job_personal_error_icon.png',width: 10.r,height: 10.r,):Text('', style: TextStyle(fontSize: 12.sp, color: Color(0xFF525252))), + child: Text(CommonUtils.second2HMS(item.useTime!), style: TextStyle(fontSize: 12.sp, color: Color(0xFF525252))), ), )), DataCell(InkWell( - onTap: (){ - if(item.state==1 || item.state==2){ - ImageDialog.showImgDialog(context,item.annotateAnswers!); + onTap: () { + if (item.state != 0) { + ImageDialog.showImgDialog(context, item.studentAnswer!); } - }, child: Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(item.state==1 || item.state==2?'查看':'--', - style: TextStyle(fontSize: 12.sp, color: Color(0xFF3661FE))), + child: Text(item.state != 0 ? '查看' : '--', style: TextStyle(fontSize: 12.sp, color: Color(0xFF3661FE))), + ), + ), + )), + DataCell(Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: item.state == 2 + ? Image.asset( + 'assets/images/job_personal_correct_icon.png', + width: 18.r, + height: 18.r, + ) + : item.state == 1 + ? Image.asset( + 'assets/images/job_personal_error_icon.png', + width: 10.r, + height: 10.r, + ) + : Text('', style: TextStyle(fontSize: 12.sp, color: Color(0xFF525252))), + ), + )), + DataCell(InkWell( + onTap: () { + if (item.state == 1 || item.state == 2) { + ImageDialog.showImgDialog(context, item.annotateAnswers!); + } + }, + child: Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text(item.state == 1 || item.state == 2 ? '查看' : '--', style: TextStyle(fontSize: 12.sp, color: Color(0xFF3661FE))), ), ), )), @@ -139,14 +153,10 @@ class _StudentZgTableState extends State { headingRowHeight: 40.r, dataRowHeight: 40.r, border: TableBorder( - horizontalInside: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid), - bottom: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid), - verticalInside: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid)), - headingRowColor: MaterialStateProperty.resolveWith((states) => - widget.fixedCols! > 0 ? Colors.white : Colors.transparent), + horizontalInside: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid), + bottom: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid), + verticalInside: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid)), + headingRowColor: MaterialStateProperty.resolveWith((states) => widget.fixedCols! > 0 ? Colors.white : Colors.transparent), headingRowDecoration: BoxDecoration(color: Color(0xFFE6E6E6)), fixedColumnsColor: Color(0xFFE6E6E6), fixedCornerColor: Colors.grey[400], @@ -160,14 +170,12 @@ class _StudentZgTableState extends State { var item = widget.headList[index]; return DataColumn2( label: Center( - child: Text(item, - style: TextStyle(fontSize: 12.sp, color: Color(0xFF505767))), + child: Text(item, style: TextStyle(fontSize: 12.sp, color: Color(0xFF505767))), ), // size: ColumnSize.S, - fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r)/5, + fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r) / 5, ); }), - rows: List.generate(widget.bodyList.length, - (index) => _getRow(index, Color(0xFFF5F5F5)))); + rows: List.generate(widget.bodyList.length, (index) => _getRow(index, Color(0xFFF5F5F5)))); } } From 3666bea6bde2f01834eb57f98225e2892be813e3 Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Wed, 24 Apr 2024 18:24:17 +0800 Subject: [PATCH 24/28] no message --- .../pages/homework_correction/widget/answer_handwriting.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart index b31d7dc..7c41abb 100644 --- a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart +++ b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart @@ -416,7 +416,7 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev var _model = (e as PlaybackSpeedBus); speed = _model.speed; toGoPause(); // 先暂停再重新播放 - toGoPlay(); // 重新播放 + dragProgressBarInitData(handwritingTime, handwritingDuration); break; default: } @@ -506,8 +506,8 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev pendingData = waitingExecution; ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal(executeImmediately); - eventFire(model: JobHandwritingPlaybarBus(true)); } + eventFire(model: JobHandwritingPlaybarBus(true)); } Future zhixinCall(GestureHandwritingRecording e) async { From 919f71f28b608f24c6ddd9918f59626afaa4da2a Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Thu, 25 Apr 2024 10:59:37 +0800 Subject: [PATCH 25/28] no message --- .../widget/answer_handwriting.dart | 52 ++++++++++--------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart index 7c41abb..ac61356 100644 --- a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart +++ b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart @@ -408,15 +408,14 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev toGoPlay(); } else { // 暂停 - toGoPause(); + toGoPause(_val.recalculate); } break; case PlaybackSpeedBus: // 播放速度 var _model = (e as PlaybackSpeedBus); speed = _model.speed; - toGoPause(); // 先暂停再重新播放 - dragProgressBarInitData(handwritingTime, handwritingDuration); + dragProgressBarInitData(handwritingDuration - handwritingTime, handwritingDuration); break; default: } @@ -449,12 +448,13 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev } // 暂停播放 - Future toGoPause() async { + Future toGoPause(bool recalculate) async { timers.forEach((e) { if (e.isActive) e.cancel(); }); timers = []; - if (pendingData.isNotEmpty && handwritingTime > 0 && (handwritingDuration - handwritingTime > 0)) { + // 总时间-剩余时间=已经执行时间 + if (recalculate && pendingData.isNotEmpty && handwritingTime > 0 && (handwritingDuration - handwritingTime > 0)) { // 待执行的数据不等于空 每个数据都需要减去当前暂停已经执行的时间 pendingData = pendingData.map((e) { return GestureHandwritingRecording( @@ -470,7 +470,7 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev /// 拖动进度条后重新初始化数据 /// @param startTime 起始时间 单位秒 Future dragProgressBarInitData(int startTime, int totalDuration) async { - eventFire(model: JobHandwritingPlaybarBus(false)); + eventFire(model: JobHandwritingPlaybarBus(false, false)); timers.forEach((e) { if (e.isActive) e.cancel(); }); @@ -489,7 +489,7 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev for (var i = 0; i < _packagedHandwritingDataAll.length; i++) { var item = _packagedHandwritingDataAll[i]; - if (item.intervalTime < startTime) { + if (item.intervalTime <= startTime) { // 需要直接装配到直接打印的容器 executeImmediately.add(item); } else { @@ -515,29 +515,30 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev List trajectorys = ref.read(jobHandwritingDrawingTrajectoryProvider)..add(e); ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal(List.from(trajectorys)); pendingData.remove(e); // 执行后删除容器中的当前动作 + print('正在执行播放.............'); } } /// 开始播放 Future toGoPlay() async { - handwritingTime = 0; - var executableData = _packagedHandwritingDataAll; - if (pendingData.isNotEmpty) { - // 待执行的数据没有执行完成 就继续执行待执行数据 - executableData = pendingData; - } else { - pendingData.addAll(_packagedHandwritingDataAll); - ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); - } - - executableData.forEach((e) { - if (e.intervalTime == 0) { - zhixinCall(e); + try { + handwritingTime = 0; + var executableData = _packagedHandwritingDataAll; + if (pendingData.isNotEmpty) { + // 待执行的数据没有执行完成 就继续执行待执行数据 + executableData = pendingData; } else { + pendingData.addAll(_packagedHandwritingDataAll); + ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); + } + + executableData.forEach((e) { var ter = Timer(Duration(milliseconds: e.intervalTime ~/ speed), () => zhixinCall(e)); timers.add(ter); - } - }); + }); + } catch (e) { + print('播放报错:$e'); + } } // 计算尺寸 @@ -761,7 +762,7 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L width: unitScale * (item.apart ?? 0), height: 8.h, decoration: BoxDecoration( - color: Colors.white, + color: Color.fromRGBO(202, 201, 201, 1), borderRadius: isFirst ? BorderRadius.only(topLeft: Radius.circular(8.r), bottomLeft: Radius.circular(10.r)) : (isLast ? BorderRadius.only(topRight: Radius.circular(8.r), bottomRight: Radius.circular(10.r)) : null), @@ -780,7 +781,7 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L width: containerWidth, decoration: BoxDecoration( // color: Color.fromRGBO(146, 146, 146, 1), - color: Color.fromRGBO(202, 201, 201, 1), + color: Colors.white, borderRadius: BorderRadius.circular(50.r), ), ), @@ -920,7 +921,8 @@ class UseBottomPlaybar with EventBusMixin { // 播放按钮 class JobHandwritingPlaybarBus { bool play; - JobHandwritingPlaybarBus(this.play); + bool recalculate; + JobHandwritingPlaybarBus(this.play, [this.recalculate = true]); } // 笔迹是否已经准备好(笔迹计算好坐标后通知通知栏可以开始播放) From 17738ff29e24922f603dc73ecc99a53c82b00a70 Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Thu, 25 Apr 2024 14:33:06 +0800 Subject: [PATCH 26/28] no message --- .../homework_correction/do_papers_job.dart | 19 ++++++------ .../widget/answer_handwriting.dart | 31 +++++++++++-------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/marking_app/lib/pages/homework_correction/do_papers_job.dart b/marking_app/lib/pages/homework_correction/do_papers_job.dart index 46b95c3..703ae3c 100644 --- a/marking_app/lib/pages/homework_correction/do_papers_job.dart +++ b/marking_app/lib/pages/homework_correction/do_papers_job.dart @@ -859,16 +859,15 @@ Widget $examPaperAndScoringKeyboardView( ], ), ), - if (question.accuracy > 0) - Padding( - padding: EdgeInsets.only(bottom: 1.5.h), - child: quickText( - '正确率:${getDoubleRemoveZero(question.accuracy, question.accuracy.toString())}%', - size: 8.sp, - color: Colors.white, - align: TextAlign.end, - ), - ) + Padding( + padding: EdgeInsets.only(bottom: 1.5.h), + child: quickText( + '正确率:${getDoubleRemoveZero(question.accuracy, question.accuracy.toString())}%', + size: 8.sp, + color: Colors.white, + align: TextAlign.end, + ), + ) ], ), ), diff --git a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart index ac61356..289579a 100644 --- a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart +++ b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart @@ -124,7 +124,7 @@ class AnswerHandwritingMainBox extends HookWidget { _dataDetail, key: _useStateModel.handwritingKey, ), - $PageNumberBox(_data.pageNum), + $PageNumberBox(_data.pageNum, _data.pageCount), // 上一页按钮 $PreviousNutton( _useStateModel.pageNum.value, @@ -471,6 +471,7 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev /// @param startTime 起始时间 单位秒 Future dragProgressBarInitData(int startTime, int totalDuration) async { eventFire(model: JobHandwritingPlaybarBus(false, false)); + timers.forEach((e) { if (e.isActive) e.cancel(); }); @@ -485,7 +486,6 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev startTime = startTime * 1000; // 转为毫秒 List executeImmediately = []; // 立即执行数据 List waitingExecution = []; // 等待执行数据 - for (var i = 0; i < _packagedHandwritingDataAll.length; i++) { var item = _packagedHandwritingDataAll[i]; @@ -515,14 +515,12 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev List trajectorys = ref.read(jobHandwritingDrawingTrajectoryProvider)..add(e); ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal(List.from(trajectorys)); pendingData.remove(e); // 执行后删除容器中的当前动作 - print('正在执行播放.............'); } } /// 开始播放 Future toGoPlay() async { try { - handwritingTime = 0; var executableData = _packagedHandwritingDataAll; if (pendingData.isNotEmpty) { // 待执行的数据没有执行完成 就继续执行待执行数据 @@ -642,18 +640,25 @@ class DrawingPainter extends CustomPainter { } @swidget -Widget $pageNumberBox(int pageNum) { +Widget $pageNumberBox(int pageNum, int totalNum) { return Positioned( top: 6.h, right: 4.w, child: Container( - padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h), - decoration: BoxDecoration( - color: Color.fromRGBO(0, 0, 0, 0.47), - borderRadius: BorderRadius.circular(5.r), - ), - child: quickText('第$pageNum页', color: Colors.white, size: 10.sp), - ), + padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h), + decoration: BoxDecoration( + color: Color.fromRGBO(0, 0, 0, 0.47), + borderRadius: BorderRadius.circular(5.r), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + quickText('$pageNum', color: Colors.white, size: 11.sp, align: TextAlign.end), + quickText('/', color: Colors.white, size: 10.sp, align: TextAlign.end), + quickText('$totalNum', color: Colors.white, size: 8.sp, align: TextAlign.end), + ], + )), ); } @@ -840,7 +845,7 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L theIndex = -1; } usePlaybar.constantFastSpeed.value = PlaybackSpeed.values[theIndex + 1]; - }), + }, duration: Duration(milliseconds: 500)), child: Container( // alignment: Alignment., padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h), From 8ab319c32e03c04cd22c82304bfe3339cb849002 Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Fri, 26 Apr 2024 18:08:46 +0800 Subject: [PATCH 27/28] no message --- .../homework_correction/do_papers_job.dart | 6 +- .../use_switch_student_and_type.dart | 2 +- .../lib/pages/homework_correction/index.dart | 11 +- .../widget/answer_handwriting.dart | 296 ++++++++++-------- 4 files changed, 180 insertions(+), 135 deletions(-) diff --git a/marking_app/lib/pages/homework_correction/do_papers_job.dart b/marking_app/lib/pages/homework_correction/do_papers_job.dart index 703ae3c..5291ed9 100644 --- a/marking_app/lib/pages/homework_correction/do_papers_job.dart +++ b/marking_app/lib/pages/homework_correction/do_papers_job.dart @@ -290,7 +290,11 @@ Widget $dropdownBoxSwitchStudentsOrTypeView(BuildContext context, {required Func var _currentTab = _useSwitchStudentAndType.currentTab.value; var _pageIndex = _currentTab?.pageIndex; if (_currentTab == null || _pageIndex == null) return; - _useSwitchStudentAndType.refreshQuestionTypeData(context, taskId: taskId, exitCallback: exitCallback, getNewData: false).then((value) { + + var theLastQuestion = _currentTab.finishCount + 1 == _currentTab.total; // 当前提交的题是最后一题 + _useSwitchStudentAndType + .refreshQuestionTypeData(context, taskId: taskId, exitCallback: exitCallback, getNewData: theLastQuestion) + .then((value) { var params = MarkingTextQuestionJobTabParamsBus(taskId, _pageIndex); if (_currentTab.finishCount < _currentTab.total) { if (_currentTab.finishCount + 1 == _currentTab.total) { diff --git a/marking_app/lib/pages/homework_correction/hooks/do_papers_job/use_switch_student_and_type.dart b/marking_app/lib/pages/homework_correction/hooks/do_papers_job/use_switch_student_and_type.dart index 392b01f..c3ee127 100644 --- a/marking_app/lib/pages/homework_correction/hooks/do_papers_job/use_switch_student_and_type.dart +++ b/marking_app/lib/pages/homework_correction/hooks/do_papers_job/use_switch_student_and_type.dart @@ -140,7 +140,7 @@ class UseSwitchStudentAndType with CommonMixin, EventBusMixin { return tabJob; } } - ToastUtils.showSuccess('最后一题提交成功'); + // ToastUtils.showSuccess('最后一题提交成功'); } return tabJob; } diff --git a/marking_app/lib/pages/homework_correction/index.dart b/marking_app/lib/pages/homework_correction/index.dart index b3314ad..31788e1 100644 --- a/marking_app/lib/pages/homework_correction/index.dart +++ b/marking_app/lib/pages/homework_correction/index.dart @@ -261,19 +261,10 @@ class _HomeworkCorrectionState extends ConsumerState ), ), ), - Expanded( - flex: 1, - child: InkWell( - onTap: () { - RouterManager.router.navigateTo(context, RouterManager.jobStudentGroupPath, transition: getTransition()); - }, - child: Icon(IconData(0xe63e, fontFamily: "AlibabaIcon"), color: Color.fromRGBO(44, 48, 63, 1), size: 24.sp), - ), - ), + Expanded(flex: 1, child: SizedBox()), ], ), ), - if (_tabIndex == 1) $CompletedJobConditionFilter( controller: _tabController2, diff --git a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart index 289579a..75800ec 100644 --- a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart +++ b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart @@ -111,6 +111,7 @@ class AnswerHandwritingMainBox extends HookWidget { HandwritingInfo? _dataDetail = _useStateModel.handwritingDetail.value; if (_data == null || _dataDetail == null) return Container(); + return Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, @@ -209,7 +210,6 @@ class UseMainBoxState with CommonMixin { HandwritingInfo? getHandwritingDetail(JobHandwriting? theData) { if (theData == null) return null; - print('开始时间:${DateTime.now().millisecondsSinceEpoch}'); // 笔画分组 // var lattices = Map>.fromIterable( // theData.lattices, @@ -374,6 +374,9 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev TestQuestionsImageInfo? imagInfoModel; // 试题图片数据 late ImageStreamListener theImageStreamListener; + late ValueNotifier> _vnHandWritings; + + late RemoveListener _jobHandwritingDrawingTrajectoryListener; // 批注关闭监听 List> _packagedHandwritingDatas = []; List _packagedHandwritingDataAll = []; List pendingData = []; // 待执行数据 @@ -384,7 +387,10 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev @override void initState() { super.initState(); - + _vnHandWritings = ValueNotifier>([]); + _jobHandwritingDrawingTrajectoryListener = ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).addListener((state) { + _vnHandWritings.value = state; + }, fireImmediately: false); eventOn(callback: (e) { switch (e.runtimeType) { case JobHandwritingRunTimeBus: @@ -440,6 +446,8 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev timers.forEach((e) { if (e.isActive) e.cancel(); }); + _jobHandwritingDrawingTrajectoryListener(); + _vnHandWritings.dispose(); try { imageStream?.removeListener(theImageStreamListener); eventCancel(); @@ -471,7 +479,6 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev /// @param startTime 起始时间 单位秒 Future dragProgressBarInitData(int startTime, int totalDuration) async { eventFire(model: JobHandwritingPlaybarBus(false, false)); - timers.forEach((e) { if (e.isActive) e.cancel(); }); @@ -486,10 +493,11 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev startTime = startTime * 1000; // 转为毫秒 List executeImmediately = []; // 立即执行数据 List waitingExecution = []; // 等待执行数据 + for (var i = 0; i < _packagedHandwritingDataAll.length; i++) { var item = _packagedHandwritingDataAll[i]; - if (item.intervalTime <= startTime) { + if (item.intervalTime < startTime) { // 需要直接装配到直接打印的容器 executeImmediately.add(item); } else { @@ -499,7 +507,7 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev stroke: item.stroke, data: item.data, usageTime: item.usageTime, - intervalTime: intervalTime < 0 ? 0 : intervalTime, + intervalTime: intervalTime, )); } } @@ -569,26 +577,29 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev @override Widget build(BuildContext context) { - List points = ref.watch(jobHandwritingDrawingTrajectoryProvider); return Container( alignment: Alignment.center, - child: CustomPaint( - foregroundPainter: DrawingPainter(points: points), - // size: Size(ScreenUtil().screenWidth - 60.r, widget.boxHeight), - child: RepaintBoundary( - child: $TheCachedNetworkImage( - imageUrl: widget.image, - (context, imageProvider) { - Image imageWidget = Image(image: imageProvider, fit: BoxFit.contain); - if (imagInfoModel == null) { - imageStream?.removeListener(theImageStreamListener); - // 视图中展示图片的尺寸计算获取 - imageStream = imageWidget.image.resolve(ImageConfiguration()); - imageStream?.addListener(theImageStreamListener); - } + child: RepaintBoundary( + child: CustomPaint( + willChange: true, + isComplex: true, + foregroundPainter: HandWritingDrawingPainter(ctrl: _vnHandWritings), + // size: Size(ScreenUtil().screenWidth - 60.r, widget.boxHeight), + child: RepaintBoundary( + child: $TheCachedNetworkImage( + imageUrl: widget.image, + (context, imageProvider) { + Image imageWidget = Image(image: imageProvider, fit: BoxFit.contain); + if (imagInfoModel == null) { + imageStream?.removeListener(theImageStreamListener); + // 视图中展示图片的尺寸计算获取 + imageStream = imageWidget.image.resolve(ImageConfiguration()); + imageStream?.addListener(theImageStreamListener); + } - return imageWidget; - }, + return imageWidget; + }, + ), ), ), ), @@ -596,16 +607,9 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev } } -class DrawingPainter extends CustomPainter { - List points; - - DrawingPainter({required this.points}) : super(); - - // Paint paintBrush = Paint() - // ..color = Colors.black - // ..strokeCap = StrokeCap.round - // ..strokeWidth = 0.5.sp; - +class HandWritingDrawingPainter extends CustomPainter { + final ValueNotifier> ctrl; + HandWritingDrawingPainter({required this.ctrl}) : super(repaint: ctrl); //[定义画笔] final Paint paintBrush = Paint() //画笔颜色 @@ -613,30 +617,43 @@ class DrawingPainter extends CustomPainter { //画笔笔触类型 ..strokeCap = StrokeCap.round //是否启动抗锯齿 - // ..isAntiAlias = true + ..isAntiAlias = true //绘画风格,默认为填充 // ..style = PaintingStyle.fill //画笔的宽度 - ..strokeWidth = 0.6.r; + ..style = PaintingStyle.stroke + ..strokeWidth = 0.5.r; @override void paint(Canvas canvas, Size size) { // canvas.drawPoints(PointMode.points, thePoints, paintBrush); + canvas.save(); + + var points = ctrl.value; var _length = points.length; + print('正在绘制 ${_length}'); for (int i = 0; i < _length; i++) { GestureHandwritingRecording item = points[i]; - GestureHandwritingRecording? nextItem = i + 1 >= _length ? null : points[i + 1]; - Offset? offsetData = item.data; + GestureHandwritingRecording? nextItem = i + 1 < _length ? points[i + 1] : null; + Offset offsetData = item.data; Offset? nextOffsetData = nextItem?.data; if (nextOffsetData != null && item.stroke == nextItem?.stroke) { canvas.drawLine(offsetData, nextOffsetData, paintBrush); } } + canvas.restore(); } @override - bool shouldRepaint(DrawingPainter oldDelegate) => true; + bool shouldRepaint(covariant CustomPainter oldDelegate) { + if (oldDelegate is HandWritingDrawingPainter) { + var repaint = ctrl.value.length != oldDelegate.ctrl.value.length || oldDelegate.ctrl.value != ctrl.value; + print('调用是否绘制:$repaint'); + return repaint; + } + return true; // 如果 oldDelegate 不是 MyCustomPainter 的实例,则总是重绘 + } } @swidget @@ -665,11 +682,13 @@ Widget $pageNumberBox(int pageNum, int totalNum) { @hwidget Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, List pauseIntervals) { var usePlaybar = UseBottomPlaybar.use(timeConsuming); - useValueChanged(timeConsuming, (_, __) { + usePlaybar.playTimingSuspend(); + usePlaybar.playPause.value = false; var seds = timeConsuming ~/ 1000; if ((timeConsuming % 1000) > 500) seds += 1; usePlaybar.handwritingDuration.value = seds; + usePlaybar.constantFastSpeed.value = PlaybackSpeed.ORIGINAL_SPEED; }); useValueChanged(usePlaybar.handwritingDuration.value, (_, __) { @@ -700,11 +719,11 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L if (_val.play) { // 开始播放 usePlaybar.playTimingStarts(); - if (!usePlaybar.playPause.value) usePlaybar.playPause.value = true; + if (!usePlaybar.playPause.value) Future.delayed(Duration.zero, () => usePlaybar.playPause.value = true); } else { // 暂停播放 usePlaybar.playTimingSuspend(); - if (usePlaybar.playPause.value) usePlaybar.playPause.value = false; + if (usePlaybar.playPause.value) Future.delayed(Duration.zero, () => usePlaybar.playPause.value = false); } break; case JobHandwritingGetReadyBus: @@ -736,6 +755,8 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L if (usePlaybar.handWritingReady.value) InkWell( onTap: () => easyThrottle('job_handwriting_play_pause', () { + if (usePlaybar.handwritingDuration.value == 0) return ToastUtils.showInfo('没有笔迹'); + usePlaybar.playPause.value = !usePlaybar.playPause.value; usePlaybar.eventFire(model: JobHandwritingPlaybarBus(usePlaybar.playPause.value)); }), @@ -749,93 +770,96 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L SpinKitPouringHourGlassRefined(size: 40.sp, color: Colors.white), SizedBox(width: 6.w), Expanded( - child: LayoutBuilder( - builder: (context, constraints) { - final double containerWidth = constraints.maxWidth; // 展示区域总宽度 - // print('总刻度:$timeConsuming,宽度:$containerWidth'); - // print('总时长:${pauseIntervals.map((e) => e.toJson()).toList()}'); - var unitScale = containerWidth / timeConsuming; // 单位刻度 - var pauseIntervalsLength = pauseIntervals.length; - List pauseTickMarks = pauseIntervals.asMap().keys.map((e) { - bool isLast = e == pauseIntervalsLength - 1; - bool isFirst = e == 0; - var item = pauseIntervals[e]; - return Positioned( - top: 0, - left: unitScale * item.startTime, - child: Container( - width: unitScale * (item.apart ?? 0), - height: 8.h, - decoration: BoxDecoration( - color: Color.fromRGBO(202, 201, 201, 1), - borderRadius: isFirst - ? BorderRadius.only(topLeft: Radius.circular(8.r), bottomLeft: Radius.circular(10.r)) - : (isLast ? BorderRadius.only(topRight: Radius.circular(8.r), bottomRight: Radius.circular(10.r)) : null), - ), - ), - ); - }).toList(); + child: LayoutBuilder(builder: (context, constraints) { + final double containerWidth = constraints.maxWidth; // 展示区域总宽度 + var unitScale = containerWidth / timeConsuming; // 单位刻度 + var pauseIntervalsLength = pauseIntervals.length; - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - Stack( - children: [ - Container( - height: 8.h, - width: containerWidth, - decoration: BoxDecoration( - // color: Color.fromRGBO(146, 146, 146, 1), - color: Colors.white, - borderRadius: BorderRadius.circular(50.r), - ), - ), - ...pauseTickMarks, - Container( - height: 8.h, - // color: Theme.of(context).primaryColor, - child: SliderTheme( - data: SliderTheme.of(context).copyWith( - trackHeight: 8.h, // 轨道高度 - trackShape: RoundedRectSliderTrackShape(), // 轨道形状,可以自定义 - activeTrackColor: Theme.of(context).primaryColor, // 激活的轨道颜色 - inactiveTrackColor: Colors.transparent, // 未激活的轨道颜色 - thumbShape: RoundSliderThumbShape(enabledThumbRadius: 0, disabledThumbRadius: 0), - thumbColor: Colors.white, // 滑块颜色 - overlayShape: RoundSliderOverlayShape(overlayRadius: 0), - overlayColor: Colors.black54, // 滑块外圈颜色 - // valueIndicatorShape: PaddleSliderValueIndicatorShape(), // 标签形状,可以自定义 - ), - child: Slider( - value: (usePlaybar.handwritingDuration.value - usePlaybar.useTime.value).toDouble(), - min: 0.0, - max: usePlaybar.handwritingDuration.value.toDouble(), - inactiveColor: Colors.transparent, - onChangeEnd: (value) { - usePlaybar.playTimingSuspend(); // 暂停计时器得暂停 - usePlaybar.eventFire(model: JobHandwritingDragProgressBarBus(value.toInt(), usePlaybar.handwritingDuration.value)); - usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); - }, - onChanged: (double value) { - usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); - }, - ), - ), - ), - ], + List pauseTickMarks = pauseIntervals.asMap().keys.map((e) { + bool isLast = e == pauseIntervalsLength - 1; + bool isFirst = e == 0; + var item = pauseIntervals[e]; + return Positioned( + top: 0, + left: unitScale * item.startTime, + child: Container( + width: unitScale * (item.apart ?? 0), + height: 8.h, + decoration: BoxDecoration( + color: Color.fromRGBO(202, 201, 201, 1), + borderRadius: isFirst + ? BorderRadius.only(topLeft: Radius.circular(8.r), bottomLeft: Radius.circular(10.r)) + : (isLast ? BorderRadius.only(topRight: Radius.circular(8.r), bottomRight: Radius.circular(10.r)) : null), ), - SizedBox(height: 4.h), - Row( + ), + ); + }).toList(); + + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Stack( + children: [ + Container( + height: 8.h, + width: containerWidth, + decoration: BoxDecoration( + // color: Color.fromRGBO(146, 146, 146, 1), + color: Colors.white, + borderRadius: BorderRadius.circular(50.r), + ), + ), + ...pauseTickMarks, + Container( + height: 8.h, + width: containerWidth, + // color: Theme.of(context).primaryColor, + child: SliderTheme( + data: SliderTheme.of(context).copyWith( + trackHeight: 8.h, // 轨道高度 + trackShape: RoundedRectSliderTrackShape(), // 轨道形状,可以自定义 + activeTrackColor: Theme.of(context).primaryColor, // 激活的轨道颜色 + inactiveTrackColor: Colors.transparent, // 未激活的轨道颜色 + thumbShape: RoundSliderThumbShape(enabledThumbRadius: 0, disabledThumbRadius: 0), + thumbColor: Colors.white, // 滑块颜色 + overlayShape: RoundSliderOverlayShape(overlayRadius: 0), + overlayColor: Colors.black54, // 滑块外圈颜色 + // valueIndicatorShape: PaddleSliderValueIndicatorShape(), // 标签形状,可以自定义 + ), + child: Slider( + value: (usePlaybar.handwritingDuration.value - usePlaybar.useTime.value).toDouble(), + min: 0.0, + max: usePlaybar.handwritingDuration.value.toDouble(), + inactiveColor: Colors.transparent, + onChangeEnd: (value) { + if (!usePlaybar.handWritingReady.value) return; + usePlaybar.playTimingSuspend(); // 暂停计时器得暂停 + usePlaybar.eventFire(model: JobHandwritingDragProgressBarBus(value.toInt(), usePlaybar.handwritingDuration.value)); + usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); + }, + onChanged: (double value) { + if (!usePlaybar.handWritingReady.value) return; + usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt(); + }, + ), + ), + ), + ], + ), + SizedBox(height: 4.h), + SizedBox( + width: containerWidth, + child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ quickText('累计停顿:$pauseCount次', color: Colors.white, size: 7.sp), quickText(convertSeconds(usePlaybar.useTime.value)?.toString() ?? '', color: Colors.white, size: 7.sp), ], - ) - ], - ); - }, - ), + ), + ) + ], + ); + }), ), SizedBox(width: 16.w), InkWell( @@ -863,9 +887,34 @@ Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, L ); } -@swidget -Widget $pauseTickMark() { - return Container(); +class SysjTime extends StatefulWidget { + const SysjTime({super.key}); + + @override + State createState() => _SysjTimeState(); +} + +class _SysjTimeState extends State with EventBusMixin { + int useTime = 0; + @override + void initState() { + super.initState(); + eventOn(callback: (JobHandwritingRunTimeBus e) { + useTime = e.runTimeVal; + toUpState(setState, () {}, mounted); + }); + } + + @override + void dispose() { + eventCancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return quickText(convertSeconds(useTime)?.toString() ?? '', color: Colors.white, size: 7.sp); + } } class UseBottomPlaybar with EventBusMixin { @@ -908,6 +957,7 @@ class UseBottomPlaybar with EventBusMixin { timer.value = Timer.periodic(Duration(milliseconds: 1000 ~/ constantFastSpeed.value.speed), (theTime) { useTime.value -= 1; if (useTime.value < 0) { + theTime.cancel(); timer.value?.cancel(); timer.value = null; useTime.value = handwritingDuration.value; From 89e15ba6726901870447d650e57040f438c6b7eb Mon Sep 17 00:00:00 2001 From: "1147192855@qq.com" <1147192855@qq.com> Date: Sun, 28 Apr 2024 09:28:57 +0800 Subject: [PATCH 28/28] no message --- .../pages/homework_correction/widget/answer_handwriting.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart index 75800ec..c167ebf 100644 --- a/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart +++ b/marking_app/lib/pages/homework_correction/widget/answer_handwriting.dart @@ -568,6 +568,8 @@ class _HandwritingDrawBoxState extends ConsumerState with Ev ); }).toList(); + newTrajectoryData.sort((a, b) => a.usageTime.compareTo(b.usageTime)); + _packagedHandwritingDatas.add(newTrajectoryData); // 分组数据 _packagedHandwritingDataAll.addAll(newTrajectoryData); // 不分组数据 } @@ -631,7 +633,6 @@ class HandWritingDrawingPainter extends CustomPainter { var points = ctrl.value; var _length = points.length; - print('正在绘制 ${_length}'); for (int i = 0; i < _length; i++) { GestureHandwritingRecording item = points[i]; GestureHandwritingRecording? nextItem = i + 1 < _length ? points[i + 1] : null;