1148 lines
44 KiB
Dart
1148 lines
44 KiB
Dart
import 'package:achievement_view/achievement_view.dart';
|
||
import 'package:flutter/cupertino.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter/services.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:hooks_riverpod/hooks_riverpod.dart';
|
||
import 'package:json_annotation/json_annotation.dart';
|
||
import 'package:marking_app/common/mixin/common.dart';
|
||
import 'package:marking_app/common/model/common/base_page_data_report.dart';
|
||
import 'package:marking_app/common/model/common/base_structure_result_report.dart';
|
||
import 'package:marking_app/common/model/enum/reportUserIdentity.dart';
|
||
import 'package:marking_app/common/model/report/exam_records.dart';
|
||
import 'package:marking_app/common/model/report/exam_records_all.dart';
|
||
import 'package:marking_app/common/model/report/exam_records_params.dart';
|
||
import 'package:marking_app/common/model/report/report_histogram_model.dart';
|
||
import 'package:marking_app/common/model/report/report_home_model.dart';
|
||
import 'package:marking_app/common/model/user/user_info.dart';
|
||
import 'package:marking_app/common/model/user/user_info_report.dart';
|
||
import 'package:marking_app/pages/report_detail/widgets/no_data.dart';
|
||
import 'package:marking_app/pages/reports/bar_chart_histogram.dart';
|
||
import 'package:marking_app/pages/reports/services/report_home_services.dart';
|
||
import 'package:marking_app/provider/user_provider.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_report.dart';
|
||
import 'package:percent_indicator/linear_percent_indicator.dart';
|
||
|
||
import 'widgets/myDrawer.dart';
|
||
import 'widgets/userInfo.dart';
|
||
|
||
part 'index.g.dart';
|
||
|
||
class TheReport extends StatefulHookConsumerWidget {
|
||
const TheReport({Key? key}) : super(key: key);
|
||
|
||
@override
|
||
_TheReportState createState() => _TheReportState();
|
||
}
|
||
|
||
class _TheReportState extends ConsumerState<TheReport>
|
||
with CommonMixin, AutomaticKeepAliveClientMixin {
|
||
late RemoveListener _userReportListener;
|
||
late RestClientReport ClientReport;
|
||
|
||
late UserInfo _user;
|
||
late UserInfoReport _userReport;
|
||
late Future<ReportHomeModel?> _future;
|
||
int? theExamId;
|
||
List gradeList = [];
|
||
List testTypeList = [];
|
||
List selectList = [];
|
||
bool isGrade = false;
|
||
ComboData currentGrade = ComboData('', '');
|
||
ComboData currentTestType = ComboData('', '');
|
||
List<ExamRecords> reportList = [];
|
||
bool showGrade = false;
|
||
|
||
@override
|
||
bool get wantKeepAlive => true;
|
||
|
||
@override
|
||
void initState() {
|
||
getHomeComboExam();
|
||
// getExamTypeList();
|
||
// getGradeEnumList();
|
||
|
||
// _future = initData();
|
||
Future.delayed(Duration.zero, () {
|
||
_user = ref.read(userProvider);
|
||
_userReportListener = ref.read(userReportProvider.notifier).addListener(
|
||
(state) {
|
||
_userReport = state;
|
||
if (_userReport.normal) {
|
||
// _future = initData();
|
||
toUpState(setState, () {}, mounted);
|
||
}
|
||
},
|
||
);
|
||
});
|
||
super.initState();
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
_userReportListener();
|
||
super.dispose();
|
||
}
|
||
|
||
//获取考试类别、年级
|
||
void getHomeComboExam() async {
|
||
RestClientReport clientReport = await getClientReport();
|
||
BaseStructureResultReport<ExamRecordsAll> res =
|
||
await clientReport.getHomeCombo();
|
||
testTypeList = res.data!.type.comboData;
|
||
gradeList = res.data!.grade.comboData;
|
||
testTypeList[0].isCheck = true;
|
||
gradeList[0].isCheck = true;
|
||
setState(() {
|
||
currentTestType = testTypeList[0];
|
||
currentGrade = gradeList[0];
|
||
});
|
||
// getExamRecordsList();
|
||
getLevel();
|
||
}
|
||
|
||
//获取考试类别
|
||
/* void getExamTypeList() async {
|
||
RestClientReport clientReport = await getClientReport();
|
||
BaseStructureResultReport<ExamType> res = await clientReport.getExamType();
|
||
testTypeList = res.data!.comboData;
|
||
testTypeList[0].isCheck = true;
|
||
setState(() {
|
||
currentTestType = testTypeList[0];
|
||
});
|
||
}*/
|
||
/* //获取年级
|
||
void getGradeEnumList() async {
|
||
RestClientReport clientReport = await getClientReport();
|
||
BaseStructureResultReport<List<ComboData>> result = await clientReport.getGradeEnum();
|
||
gradeList = result.data!;
|
||
|
||
print(gradeList);
|
||
gradeList[0].isCheck = true;
|
||
setState(() {
|
||
currentGrade = gradeList[0];
|
||
});
|
||
}*/
|
||
//获取列表数据
|
||
void getExamRecordsList() async {
|
||
RestClientReport clientReport = await getClientReport();
|
||
ExamRecordsParams params = ExamRecordsParams(
|
||
reportType: currentTestType.value,
|
||
grade: currentGrade.value,
|
||
page: 1,
|
||
limit: 10);
|
||
BaseStructureResultReport<BasePageDataReport<ExamRecords>> result =
|
||
await clientReport.getExamrecords(params);
|
||
setState(() {
|
||
reportList = result.data!.items;
|
||
});
|
||
|
||
}
|
||
|
||
void checkHandle(item) {
|
||
setState(() {
|
||
if (isGrade) {
|
||
gradeList.forEach((element) {
|
||
element.isCheck = false;
|
||
});
|
||
item.isCheck = true;
|
||
currentGrade = item;
|
||
} else {
|
||
testTypeList.forEach((element) {
|
||
element.isCheck = false;
|
||
});
|
||
item.isCheck = true;
|
||
currentTestType = item;
|
||
}
|
||
});
|
||
}
|
||
|
||
void getLevel() async {
|
||
getExamRecordsList();
|
||
RestClientReport clientReport = await getClientReport();
|
||
BaseStructureResultReport res =
|
||
await clientReport.getPositionlevel(currentGrade.text);
|
||
if (res.data <= 3) {
|
||
showGrade = true;
|
||
}else{
|
||
showGrade = false;
|
||
}
|
||
}
|
||
|
||
/// 初始化数据
|
||
Future<ReportHomeModel?> initData({int? examId}) async {
|
||
try {
|
||
RestClientReport clientReport = await getClientReport();
|
||
UserInfoReport _userReport = ref.read(userReportProvider);
|
||
if (!_userReport.normal) {
|
||
if(ref.read(userProvider).id == '540117143121989') return null;
|
||
// 用户职位数据是否已经请求,在主页已经请求一次 为正常使用 备用
|
||
bool theFlag =
|
||
await ref.read(userReportProvider.notifier).initUserReport();
|
||
if (!theFlag) {
|
||
return ToastUtils.showError('请求失败请重试');
|
||
}
|
||
}
|
||
BaseStructureResultReport<ReportHomeModel> res =
|
||
await clientReport.getReportHomeData(examId);
|
||
if (res.success) {
|
||
return res.data;
|
||
} else {
|
||
ToastUtils.showError(res.message ?? '请求错误,请重试');
|
||
}
|
||
} catch (e) {
|
||
if (e is CheckedFromJsonException) {
|
||
// JSON 解析失败,处理异常
|
||
toPrint(val: 'JSON 解析失败: ${e.message}');
|
||
toPrint(val: 'JSON 解析失败,出错字段: ${e.key}');
|
||
} else {
|
||
// 其他异常,处理其他错误
|
||
toPrint(val: '发生了其他错误: $e');
|
||
}
|
||
return null;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
var _scaffoldkey = new GlobalKey<ScaffoldState>(); //将Scaffold设置为全局变量
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
super.build(context); //调用super.build(返回值始终返回null,应将其忽略)
|
||
final userState = ref.watch(userProvider);
|
||
return AnnotatedRegion(
|
||
value: const SystemUiOverlayStyle(
|
||
systemNavigationBarColor: Color(0xFF000000),
|
||
systemNavigationBarDividerColor: null,
|
||
statusBarColor: Colors.transparent,
|
||
systemNavigationBarIconBrightness: Brightness.light,
|
||
statusBarIconBrightness: Brightness.dark,
|
||
statusBarBrightness: Brightness.light,
|
||
),
|
||
child: Scaffold(
|
||
key: _scaffoldkey,
|
||
drawer: MyDrawer(
|
||
list: selectList,
|
||
isGrade: isGrade,
|
||
onChanged: checkHandle,
|
||
refresh: getLevel),
|
||
body: Column(
|
||
children: [
|
||
Container(
|
||
color: Colors.white,
|
||
padding: EdgeInsets.only(
|
||
top: MediaQuery.of(context).padding.top + 4.h,
|
||
left: 14.w,
|
||
right: 14.w,
|
||
bottom: 19.h),
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
children: [
|
||
Expanded(
|
||
child: TopUserInfo(),
|
||
),
|
||
/* InkWell(
|
||
onTap: () {},
|
||
child: Text(
|
||
'历史报告',
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
color: Color.fromRGBO(128, 128, 128, 1)),
|
||
),
|
||
),*/
|
||
],
|
||
),
|
||
),
|
||
Expanded(
|
||
child: Padding(
|
||
padding: EdgeInsets.only(left: 14.w, right: 14.w),
|
||
child: Column(
|
||
children: [
|
||
SizedBox(
|
||
height: 50.r,
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.start,
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
Image.asset(
|
||
'assets/images/school_icon.png',
|
||
width: 22.w,
|
||
height: 22.w,
|
||
),
|
||
Text(
|
||
userState.schoolName,
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
color: Color.fromRGBO(62, 86, 173, 1)),
|
||
)
|
||
],
|
||
),
|
||
),
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
children: [
|
||
InkWell(
|
||
onTap: () {
|
||
setState(() {
|
||
selectList = gradeList;
|
||
isGrade = true;
|
||
_scaffoldkey.currentState?.openDrawer();
|
||
});
|
||
},
|
||
child: Container(
|
||
padding: EdgeInsets.symmetric(
|
||
vertical: 8.h, horizontal: 20.r),
|
||
width:
|
||
(MediaQuery.of(context).size.width - 80.r) / 2,
|
||
child: Row(
|
||
children: [
|
||
Text(
|
||
'年级:',
|
||
style: TextStyle(
|
||
fontSize: 12.sp,
|
||
color: Color(0xFF585858)),
|
||
),
|
||
Text(
|
||
currentGrade.text,
|
||
style: TextStyle(
|
||
fontSize: 12.sp,
|
||
color: Color(0xFF6686FD)),
|
||
),
|
||
],
|
||
),
|
||
decoration: BoxDecoration(
|
||
color: Color.fromRGBO(197, 220, 255, 0.3),
|
||
borderRadius: BorderRadius.circular(20.r),
|
||
border: Border.all(
|
||
color: Color(0xFFC0DCFF), width: 1.r),
|
||
),
|
||
),
|
||
),
|
||
InkWell(
|
||
onTap: () {
|
||
setState(() {
|
||
selectList = testTypeList;
|
||
isGrade = false;
|
||
_scaffoldkey.currentState?.openDrawer();
|
||
});
|
||
},
|
||
child: Container(
|
||
padding: EdgeInsets.symmetric(
|
||
vertical: 8.h, horizontal: 20.r),
|
||
width:
|
||
(MediaQuery.of(context).size.width - 80.r) / 2,
|
||
child: Row(
|
||
children: [
|
||
Text(
|
||
'考试类别:',
|
||
style: TextStyle(
|
||
fontSize: 12.sp,
|
||
color: Color(0xFF585858)),
|
||
),
|
||
Text(
|
||
currentTestType.text,
|
||
style: TextStyle(
|
||
fontSize: 12.sp,
|
||
color: Color(0xFF6686FD)),
|
||
),
|
||
],
|
||
),
|
||
decoration: BoxDecoration(
|
||
color: Color.fromRGBO(197, 220, 255, 0.3),
|
||
borderRadius: BorderRadius.circular(20.r),
|
||
border: Border.all(
|
||
color: Color(0xFFC0DCFF), width: 1.r),
|
||
),
|
||
),
|
||
)
|
||
],
|
||
),
|
||
SizedBox(
|
||
height: 20.r,
|
||
),
|
||
|
||
Expanded(
|
||
child: reportList.length>0?ListView.builder(
|
||
itemBuilder: (BuildContext context, int index) {
|
||
var item = reportList[index];
|
||
return Container(
|
||
// padding: EdgeInsets.all(6.r),
|
||
margin: EdgeInsets.only(bottom: 20.r),
|
||
width: double.infinity,
|
||
decoration: BoxDecoration(
|
||
image: DecorationImage(
|
||
image: AssetImage(
|
||
'assets/images/reports_bg.png'),
|
||
fit: BoxFit.fill,
|
||
),
|
||
border: Border.all(
|
||
width: 1.r,
|
||
color: Color.fromRGBO(46, 91, 255, 0.2)),
|
||
borderRadius: BorderRadius.circular(5.r),
|
||
),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Padding(
|
||
padding: EdgeInsets.only(top: 5.r,bottom: 5.r,right: 2.r),
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.start,
|
||
crossAxisAlignment:
|
||
CrossAxisAlignment.center,
|
||
children: [
|
||
Container(
|
||
padding: EdgeInsets.symmetric(
|
||
vertical: 20.r, horizontal: 25.r),
|
||
decoration: BoxDecoration(
|
||
image: DecorationImage(
|
||
image: AssetImage(
|
||
'assets/images/report_group_bg.png'),
|
||
fit: BoxFit.fill,
|
||
)),
|
||
child: Text(
|
||
item.typeName,
|
||
style: TextStyle(
|
||
fontSize: 12.sp,
|
||
color: Colors.white),
|
||
),
|
||
),
|
||
Flexible(
|
||
child: Text(
|
||
item.name,
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
color: Colors.black),
|
||
),
|
||
)
|
||
],
|
||
),
|
||
),
|
||
Container(
|
||
padding:
|
||
EdgeInsets.symmetric(horizontal: 10.r),
|
||
decoration: BoxDecoration(
|
||
borderRadius: BorderRadius.circular(5.r),
|
||
),
|
||
child: Table(
|
||
defaultVerticalAlignment:
|
||
TableCellVerticalAlignment.middle,
|
||
border: TableBorder.symmetric(
|
||
inside: BorderSide(
|
||
width: 1, color: Color(0xFFD7DBF0)),
|
||
outside: BorderSide.none,
|
||
),
|
||
// borderRadius: BorderRadius.circular(5.r),
|
||
children: [
|
||
TableRow(
|
||
decoration: BoxDecoration(
|
||
color: Color(0xFFECECEC),
|
||
),
|
||
children: [
|
||
Center(
|
||
child: Container(
|
||
padding: EdgeInsets.symmetric(
|
||
vertical: 6.r),
|
||
child: Text(
|
||
'年级',
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
color: Color(0xFF8A8A8A)),
|
||
),
|
||
),
|
||
),
|
||
Center(
|
||
child: Text(
|
||
'科目',
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
color: Color(0xFF8A8A8A)),
|
||
),
|
||
),
|
||
Center(
|
||
child: Text(
|
||
'考试日期',
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
color: Color(0xFF8A8A8A)),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
TableRow(
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
),
|
||
children: [
|
||
Center(
|
||
child: Container(
|
||
padding: EdgeInsets.symmetric(
|
||
vertical: 6.r),
|
||
child: Text(
|
||
item.grade,
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
color:
|
||
Color(0xFF4A4A4A)),
|
||
),
|
||
),
|
||
),
|
||
Center(
|
||
child: Text(
|
||
item.subjectStr,
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
color: Color(0xFF4A4A4A)),
|
||
),
|
||
),
|
||
Center(
|
||
child: Text(
|
||
item.startTimeStr,
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
color: Color(0xFF4A4A4A)),
|
||
),
|
||
),
|
||
])
|
||
],
|
||
),
|
||
),
|
||
InkWell(
|
||
onTap: () {
|
||
RouterManager.router.navigateTo(
|
||
context,
|
||
RouterManager.reportDetailPath +
|
||
'?examId=${item.id}&showGrade=${showGrade}',
|
||
transition: getTransition(),
|
||
);
|
||
},
|
||
child: Container(
|
||
margin: EdgeInsets.symmetric(
|
||
horizontal: 60.r, vertical: 20.r),
|
||
padding:
|
||
EdgeInsets.symmetric(vertical: 5.r),
|
||
width: double.infinity,
|
||
decoration: BoxDecoration(
|
||
borderRadius:
|
||
BorderRadius.circular(20.r),
|
||
gradient: LinearGradient(
|
||
begin: Alignment(0.95, -0.30),
|
||
end: Alignment(-0.95, 0.3),
|
||
colors: [
|
||
Color(0xFF3561FE),
|
||
Color(0xFF6A89FC)
|
||
])),
|
||
child: Center(
|
||
child: Text(
|
||
'查看报告',
|
||
style: TextStyle(
|
||
fontSize: 16.sp,
|
||
color: Colors.white),
|
||
)),
|
||
),
|
||
)
|
||
],
|
||
),
|
||
);
|
||
},
|
||
itemCount: reportList.length,
|
||
):MyEmptyWidget(),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
)
|
||
],
|
||
)),
|
||
);
|
||
}
|
||
}
|
||
|
||
// 报告body
|
||
class _TheReportBody extends HookWidget {
|
||
final UserInfo user;
|
||
final UserInfoReport userReport;
|
||
final ReportHomeModel? data;
|
||
final Function(int? examId, int positionIndex) switchCall;
|
||
final Function() refreshReport;
|
||
|
||
_TheReportBody(
|
||
{required this.user,
|
||
required this.userReport,
|
||
required this.switchCall,
|
||
required this.refreshReport,
|
||
required this.data,
|
||
Key? key})
|
||
: super(key: key);
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
ExamData? examData = data?.examData;
|
||
List<ReportHistogramModel>? tagComparisonList = examData?.tagComparisonList
|
||
.map((e) => ReportHistogramModel(name: e.name, val: e.count))
|
||
.toList();
|
||
List<ExamSubjectDatas>? examSubjectDatas = data?.examSubjectDatas;
|
||
|
||
List<Positions> _positions = userReport.positions;
|
||
|
||
SwitchIdentityExamsController potnAndExamCotl =
|
||
SwitchIdentityExamsController.use(
|
||
position: userReport.positionIndex,
|
||
exam: -1,
|
||
initExamId: examData?.examId,
|
||
positons: userReport.positions);
|
||
Positions? theCurrentPosition = _positions.isEmpty
|
||
? null
|
||
: _positions[potnAndExamCotl.positionIndex.value];
|
||
|
||
if (examData == null || theCurrentPosition == null) {
|
||
return Padding(
|
||
padding: EdgeInsets.only(
|
||
left: 16.w, right: 16.w, top: MediaQuery.of(context).padding.top),
|
||
child: Column(
|
||
children: [
|
||
$ReportTitle(
|
||
titleName: '',
|
||
switchCall: () =>
|
||
easyThrottle('reportHomeExamSwitchCall', () async {
|
||
// switchCall(examId, potnAndExamCotl.positionIndex.value);
|
||
List<Positions> positions = userReport.positions;
|
||
if (positions.isEmpty) {
|
||
return ToastUtils.showInfo('没有数据,请刷新');
|
||
}
|
||
int? examId = await potnAndExamCotl.openSwitch(
|
||
context: context,
|
||
currentExamId: examData?.examId ?? -1,
|
||
currentPositionIndex: userReport.positionIndex);
|
||
switchCall(examId, potnAndExamCotl.positionIndex.value);
|
||
}),
|
||
),
|
||
Expanded(
|
||
child: Center(
|
||
child: Container(
|
||
child: CupertinoButton(
|
||
padding: const EdgeInsets.only(left: 10, right: 10),
|
||
color: Theme.of(context).primaryColor,
|
||
//按钮被按下时的不透明度程度,0~1之间
|
||
pressedOpacity: 1,
|
||
//这也可以自己定义Container然后固定大小进行设置等等
|
||
child:
|
||
quickText('没有数据,请重试', color: Colors.white, size: 14.sp),
|
||
onPressed: () => easyThrottle(
|
||
'reportHomeNoDataAgain', () => refreshReport()),
|
||
),
|
||
),
|
||
),
|
||
)
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
// 内容区域
|
||
return Padding(
|
||
padding: EdgeInsets.only(
|
||
left: 16.w, right: 16.w, top: MediaQuery.of(context).padding.top),
|
||
child: Column(
|
||
children: [
|
||
SizedBox(height: 6.h),
|
||
// 考试报告TITLE
|
||
$ReportTitle(
|
||
titleName: examData.examName,
|
||
switchCall: () =>
|
||
easyThrottle('reportHomeExamSwitchCall', () async {
|
||
List<Positions> positions = userReport.positions;
|
||
if (positions.isEmpty) {
|
||
return ToastUtils.showInfo('没有数据,请刷新');
|
||
}
|
||
int? examId = await potnAndExamCotl.openSwitch(
|
||
context: context,
|
||
currentExamId: examData.examId,
|
||
currentPositionIndex: userReport.positionIndex);
|
||
|
||
switchCall(examId, potnAndExamCotl.positionIndex.value);
|
||
}),
|
||
),
|
||
Expanded(
|
||
child: ScrollConfiguration(
|
||
behavior: EUMNoScrollBehavior(),
|
||
child: ListView(
|
||
padding: EdgeInsets.only(top: 20.h, bottom: 20.h),
|
||
children: [
|
||
// 顶部平均分模块
|
||
$TopAverageContainer(
|
||
averageVal: examData.averageScore,
|
||
totalVal: examData.totalScore,
|
||
context: context),
|
||
|
||
// 详细报告入口区域
|
||
$DetailedReportEntry(
|
||
context: context,
|
||
examId: examData.examId,
|
||
subjectId: theCurrentPosition.subjectId,
|
||
classId: theCurrentPosition.classId,
|
||
grade: examData.grade,
|
||
subject: examData.subjects,
|
||
examDate: examData.startTime,
|
||
identity: theCurrentPosition.identityEnum,
|
||
subjectName: theCurrentPosition.subjectName ?? '',
|
||
),
|
||
|
||
// 分段情况
|
||
$GraphicDataArea(
|
||
title: '分段概况',
|
||
titleImg: 'assets/images/report_home_icon_burst.png',
|
||
graphicContainer: Padding(
|
||
padding: EdgeInsets.only(top: 60.h, bottom: 20.h),
|
||
child: BarChartSample3(tagComparisonList!),
|
||
)),
|
||
|
||
// 单科概况
|
||
$GraphicDataArea(
|
||
title: '单科概况',
|
||
titleImg: 'assets/images/report_home_icon_subject.png',
|
||
graphicContainer:
|
||
$TheProgressChart(context, examSubjectDatas!)),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
/// 底部渐变色
|
||
@swidget
|
||
Widget $scaffoldBgc() {
|
||
return Container(
|
||
height: ScreenUtil().screenHeight,
|
||
width: ScreenUtil().screenWidth,
|
||
decoration: BoxDecoration(
|
||
gradient: LinearGradient(
|
||
begin: Alignment.topCenter,
|
||
end: Alignment.bottomCenter,
|
||
colors: [Color.fromRGBO(226, 232, 255, 1), Colors.white, Colors.white],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
// 页面TITLE
|
||
@swidget
|
||
Widget $reportTitle({required String titleName, required switchCall}) {
|
||
return Stack(
|
||
alignment: const FractionalOffset(0.98, 0.5),
|
||
children: [
|
||
Container(
|
||
padding: EdgeInsets.only(right: titleName.length > 14 ? 50 : 0).w,
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
Expanded(
|
||
child: Center(
|
||
child: quickText(
|
||
titleName,
|
||
size: 16.sp,
|
||
color: Color.fromRGBO(45, 56, 76, 1),
|
||
fontWeight: FontWeight.w600,
|
||
maxLines: 2,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
InkWell(
|
||
onTap: () =>
|
||
easyThrottle('switchRoleExamSheetCall', () => switchCall()),
|
||
child: Row(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
Icon(Icons.swap_vert_rounded,
|
||
color: Color.fromRGBO(80, 87, 103, 0.8), size: 16.sp),
|
||
quickText('切换', color: Color.fromRGBO(80, 87, 103, 1), size: 12.sp),
|
||
],
|
||
),
|
||
)
|
||
],
|
||
);
|
||
}
|
||
|
||
/// 顶部平均分模块
|
||
@swidget
|
||
Widget $topAverageContainer(
|
||
{required double averageVal,
|
||
required double totalVal,
|
||
required BuildContext context}) {
|
||
return Stack(
|
||
alignment: const FractionalOffset(0.99, 0),
|
||
children: [
|
||
Container(
|
||
padding: EdgeInsets.only(left: 12.w),
|
||
child: Row(
|
||
children: [
|
||
Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
ClipRRect(
|
||
borderRadius: BorderRadius.circular(3).r,
|
||
child: Container(
|
||
alignment: Alignment.centerLeft,
|
||
padding:
|
||
EdgeInsets.only(left: 4, right: 4, top: 4, bottom: 7).r,
|
||
child: quickText('平均分', size: 6.sp, color: Colors.white),
|
||
decoration: ShapeDecoration(
|
||
shape: BeveledRectangleBorder(
|
||
borderRadius: BorderRadius.only(
|
||
topLeft: Radius.circular(2).r,
|
||
topRight: Radius.circular(2).r,
|
||
bottomLeft: Radius.circular(15).r,
|
||
bottomRight: Radius.circular(15).r,
|
||
),
|
||
),
|
||
gradient: LinearGradient(
|
||
begin: Alignment.topCenter,
|
||
end: Alignment.bottomCenter,
|
||
colors: [
|
||
Theme.of(context).primaryColor,
|
||
Theme.of(context).primaryColor.withOpacity(0.3)
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
SizedBox(height: 1.h),
|
||
quickText(averageVal.toString(),
|
||
size: 38.sp,
|
||
color: Color.fromRGBO(45, 56, 76, 1),
|
||
fontWeight: FontWeight.bold),
|
||
SizedBox(height: 1.h),
|
||
quickText('满分' + totalVal.toString(),
|
||
size: 12.sp, color: Color.fromRGBO(80, 87, 103, 0.7)),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
Image.asset("assets/images/report_home_top_img.png",
|
||
width: 100.r, height: 100.r)
|
||
],
|
||
);
|
||
}
|
||
|
||
/// 详细报告入口模块
|
||
@swidget
|
||
Widget $detailedReportEntry({
|
||
required String grade,
|
||
required String subject,
|
||
required String examDate,
|
||
required int examId,
|
||
required int? classId,
|
||
required int? subjectId,
|
||
required ReportUserIdentity identity,
|
||
required String subjectName,
|
||
required BuildContext context,
|
||
}) {
|
||
return Container(
|
||
width: double.infinity,
|
||
margin: EdgeInsets.only(top: 6.h, bottom: 28.h),
|
||
// constraints: BoxConstraints(
|
||
// minHeight: 140.h,
|
||
// minWidth: double.infinity,
|
||
// maxHeight: 160.h,
|
||
// maxWidth: double.infinity,
|
||
// ),
|
||
padding: EdgeInsets.symmetric(horizontal: 18.w, vertical: 16.h),
|
||
decoration: BoxDecoration(
|
||
image: DecorationImage(
|
||
image: AssetImage('assets/images/detailed_report_entry_bgm.png'),
|
||
fit: BoxFit.fill,
|
||
),
|
||
),
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
children: [
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
quickText('年级',
|
||
size: 12.sp, color: Color.fromRGBO(80, 87, 103, 1)),
|
||
SizedBox(height: 5.h),
|
||
quickText(grade,
|
||
size: 16.sp,
|
||
fontWeight: FontWeight.bold,
|
||
color: Color.fromRGBO(45, 56, 76, 1)),
|
||
],
|
||
),
|
||
SizedBox(width: 23.w),
|
||
Expanded(
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
quickText('学科',
|
||
size: 12.sp, color: Color.fromRGBO(80, 87, 103, 1)),
|
||
SizedBox(height: 5.h),
|
||
quickText(subject,
|
||
size: 16.sp,
|
||
fontWeight: FontWeight.bold,
|
||
color: Color.fromRGBO(45, 56, 76, 1),
|
||
maxLines: 2),
|
||
],
|
||
)
|
||
],
|
||
),
|
||
),
|
||
SizedBox(width: 23.w),
|
||
Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
quickText('考试日期',
|
||
size: 12.sp, color: Color.fromRGBO(80, 87, 103, 1)),
|
||
SizedBox(height: 5.h),
|
||
quickText(examDate,
|
||
size: 16.sp,
|
||
fontWeight: FontWeight.bold,
|
||
color: Color.fromRGBO(45, 56, 76, 1)),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
SizedBox(height: 30.h),
|
||
InkWell(
|
||
onTap: () => easyThrottle('reportToUserPositionDetails', () {
|
||
String rootPath;
|
||
switch (identity) {
|
||
case ReportUserIdentity.TEACHER: // 单科老师
|
||
rootPath = RouterManager.reportSubjectTeacherPath +
|
||
'?examId=$examId&classId=$classId&subject=$subjectId&subjectName=${Uri.encodeComponent(subjectName)}';
|
||
break;
|
||
case ReportUserIdentity.CLASS: // 班主任
|
||
rootPath =
|
||
RouterManager.reportClassTeacherPath + '?examId=$examId';
|
||
break;
|
||
case ReportUserIdentity.GRADE: // 年级
|
||
case ReportUserIdentity.SCHOOL_LEVEL: // 校级
|
||
case ReportUserIdentity.STATE_EDUCATION_COMMISSION: // 国家教育委员会
|
||
default:
|
||
rootPath = '';
|
||
return AchievementView(
|
||
elevation: 0.5,
|
||
duration: Duration(seconds: 1),
|
||
title: "提示",
|
||
subTitle: "当前职位详情还未开放,请稍后",
|
||
color: Theme.of(context).primaryColor,
|
||
).show(context);
|
||
}
|
||
RouterManager.router
|
||
.navigateTo(context, rootPath, transition: getTransition());
|
||
}),
|
||
child: Container(
|
||
width: double.infinity,
|
||
margin: EdgeInsets.symmetric(horizontal: 25.w),
|
||
padding: EdgeInsets.symmetric(vertical: 9.h),
|
||
alignment: Alignment.center,
|
||
decoration: BoxDecoration(
|
||
borderRadius: BorderRadius.circular(80).r,
|
||
gradient: LinearGradient(
|
||
begin: Alignment.topCenter,
|
||
end: Alignment.bottomCenter,
|
||
colors: [
|
||
Color.fromRGBO(54, 86, 255, 1),
|
||
Color.fromRGBO(93, 128, 255, 1)
|
||
],
|
||
),
|
||
boxShadow: [
|
||
BoxShadow(
|
||
color: Color.fromRGBO(46, 91, 255, 0.4),
|
||
offset: Offset(2.0, 2.0), //阴影xy轴偏移量
|
||
blurRadius: 15.0, //阴影模糊程度
|
||
spreadRadius: 1.0, //阴影扩散程度
|
||
)
|
||
],
|
||
),
|
||
child: quickText('查看详细报告',
|
||
color: Colors.white, size: 14.sp, fontWeight: FontWeight.w400),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 图形数据模块
|
||
@swidget
|
||
Widget $graphicDataArea(
|
||
{required String title,
|
||
required String titleImg,
|
||
required Widget graphicContainer}) {
|
||
return Container(
|
||
margin: EdgeInsets.only(bottom: 28.h),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
Row(
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
Image.asset(titleImg, width: 22.w, height: 22.h),
|
||
SizedBox(width: 2.w),
|
||
quickText(title, size: 16.sp, color: Color.fromRGBO(45, 56, 76, 1)),
|
||
],
|
||
),
|
||
SizedBox(height: 6.h),
|
||
Card(
|
||
elevation: 11.h,
|
||
shadowColor: Color.fromRGBO(46, 91, 255, 0.10),
|
||
borderOnForeground: true,
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(6).r,
|
||
side: BorderSide(color: Colors.white, width: 1.4.r),
|
||
),
|
||
child: graphicContainer,
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 进度图
|
||
@swidget
|
||
Widget $theProgressChart(context, List<ExamSubjectDatas> datas) {
|
||
bool isMultiple = datas.length > 1; // 是不是多个数据
|
||
|
||
return Container(
|
||
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 19.h),
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
borderRadius: BorderRadius.circular(6).r,
|
||
gradient: LinearGradient(
|
||
begin: Alignment.topCenter,
|
||
end: Alignment.bottomCenter,
|
||
colors: [Color.fromRGBO(249, 250, 255, 1), Colors.white],
|
||
),
|
||
),
|
||
child: Column(
|
||
children: [
|
||
/// 平均分
|
||
...datas.map((e) {
|
||
return $theProgressWidget(
|
||
context: context,
|
||
isMultiple: isMultiple,
|
||
linearGradient: LinearGradient(
|
||
colors: [Colors.white, Theme.of(context).primaryColor]),
|
||
subjectName: e.subjectName + '平均分',
|
||
suffixTitle: e.totalScoreStr + '分',
|
||
contentVal: e.averageScoreStr + '分',
|
||
percent: e.averagePercent,
|
||
contentColor: Theme.of(context).primaryColor,
|
||
);
|
||
}),
|
||
|
||
SizedBox(height: 20.h),
|
||
|
||
/// 通过率
|
||
...datas.map((e) {
|
||
return $theProgressWidget(
|
||
context: context,
|
||
isMultiple: isMultiple,
|
||
linearGradient: LinearGradient(
|
||
colors: [Colors.white, Color.fromRGBO(0, 131, 253, 1)]),
|
||
subjectName: e.subjectName + '及格率',
|
||
suffixTitle: '100%',
|
||
contentVal: e.passRateStr + '%',
|
||
percent: e.passPercent,
|
||
contentColor: Color.fromRGBO(0, 131, 253, 1),
|
||
);
|
||
})
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 进度条图
|
||
@swidget
|
||
Widget $theProgressWidget({
|
||
required bool isMultiple,
|
||
required BuildContext context,
|
||
required LinearGradient linearGradient,
|
||
required String subjectName,
|
||
required String suffixTitle,
|
||
required String contentVal,
|
||
required Color contentColor,
|
||
required double percent,
|
||
}) {
|
||
return Padding(
|
||
padding: EdgeInsets.only(top: isMultiple ? 4.h : 0),
|
||
child: Stack(
|
||
alignment: const FractionalOffset(0.5, 0.45),
|
||
children: [
|
||
Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
quickText(subjectName,
|
||
size: 14.sp,
|
||
color: Color.fromRGBO(45, 56, 76, 1),
|
||
fontWeight: FontWeight.w400),
|
||
SizedBox(height: 6.h),
|
||
Row(
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
Expanded(
|
||
child: LinearPercentIndicator(
|
||
padding:
|
||
const EdgeInsets.symmetric(horizontal: 0, vertical: 0),
|
||
// width: MediaQuery.of(context).size.width - 50,
|
||
animation: true,
|
||
lineHeight: 9.h,
|
||
animationDuration: 2500,
|
||
percent: percent,
|
||
linearGradient: linearGradient,
|
||
// center: Text(
|
||
// '${markingItem.completionRateStr}%',
|
||
// style: TextStyle(color: Colors.white, fontSize: 10.sp),
|
||
// ),
|
||
// linearStrokeCap: LinearStrokeCap.butt,
|
||
// progressColor: Theme.of(context).primaryColor,
|
||
backgroundColor: const Color.fromRGBO(219, 224, 243, 1)
|
||
.withOpacity(0.45),
|
||
barRadius: Radius.circular(10.h),
|
||
),
|
||
),
|
||
Container(
|
||
width: 42.w,
|
||
alignment: Alignment.centerRight,
|
||
// padding: EdgeInsets.only(left: 20.w),suffixTitle
|
||
child: quickText(suffixTitle,
|
||
size: 12.sp,
|
||
color: Color.fromRGBO(148, 163, 182, 1),
|
||
fontWeight: FontWeight.w400),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
quickText(contentVal,
|
||
size: 12.sp, fontWeight: FontWeight.w700, color: contentColor),
|
||
],
|
||
),
|
||
);
|
||
}
|