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 0000000..87bb071 Binary files /dev/null and b/marking_app/assets/images/right_icon_blue.png differ 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 8bd1319..8bee856 100644 --- a/marking_app/lib/pages/homework_correction/index.dart +++ b/marking_app/lib/pages/homework_correction/index.dart @@ -274,13 +274,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 0470c24..ab530a2 100644 --- a/marking_app/lib/routes/RouterManager.dart +++ b/marking_app/lib/routes/RouterManager.dart @@ -7,12 +7,15 @@ * @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_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'; @@ -78,6 +81,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 @@ -101,14 +106,18 @@ 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]); @@ -127,8 +136,11 @@ 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 { @@ -170,7 +182,8 @@ 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]); @@ -214,7 +227,8 @@ 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); @@ -284,7 +298,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); }, ); @@ -302,7 +316,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); }, ); @@ -326,7 +340,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); }, ); @@ -335,7 +349,7 @@ 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); }, ); @@ -347,7 +361,7 @@ class RouterManager { // 学生报告详情 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);*/ }, @@ -355,11 +369,29 @@ 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(); }, ); + + // 知识点掌握 + 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()); @@ -377,28 +409,38 @@ 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); + 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)); // 加上天数差减一,得到本周日的时间 + } + + }