456 lines
16 KiB
Dart
456 lines
16 KiB
Dart
/*
|
|
* @Author: wangyang 1147192855@qq.com
|
|
* @Date: 2022-07-15 09:14:59
|
|
* @LastEditors: wangyang 1147192855@qq.com
|
|
* @LastEditTime: 2022-07-29 10:22:25
|
|
* @FilePath: \marking_app\lib\pages\marking\progress.dart
|
|
* @Description: 进度页面
|
|
*/
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_easyrefresh/easy_refresh.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:marking_app/common/config/request_config.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:marking_app/common/mixin/common.dart';
|
|
import 'package:marking_app/common/model/common/base_page_data.dart';
|
|
import 'package:marking_app/common/model/common/base_structure_result.dart';
|
|
import 'package:marking_app/common/model/progress/progress_item.dart';
|
|
import 'package:marking_app/common/model/progress/progress_page_params.dart';
|
|
import 'package:marking_app/common/model/progress/progress_statistics.dart';
|
|
import 'package:marking_app/utils/easy_refresh/mixin/refresh_data_handle.dart';
|
|
import 'package:percent_indicator/linear_percent_indicator.dart';
|
|
|
|
class Progress extends StatefulWidget {
|
|
final String name;
|
|
final int examSubjectId;
|
|
const Progress(this.examSubjectId, this.name, {Key? key}) : super(key: key);
|
|
|
|
@override
|
|
State<Progress> createState() => ProgressState();
|
|
}
|
|
|
|
class ProgressState extends State<Progress>
|
|
with SingleTickerProviderStateMixin, CommonMixin, RefreshDataHandle<ProgressItem, ProgressPageParams> {
|
|
late final String name;
|
|
late final int examSubjectId;
|
|
late ProgressPageParams pageParams;
|
|
List<ProgressItem> listData = [];
|
|
ProgressStatistics statisticsData = ProgressStatistics(0, 0, 0, 0, 0); /* 发起请求获取统计数据 */
|
|
late final EasyRefreshController _refreshController;
|
|
|
|
/*
|
|
* 获取统计数据
|
|
* getDataForStatistics
|
|
*/
|
|
void getDataForStatistics() async {
|
|
RestClient client = await getClient();
|
|
BaseStructureResult<ProgressStatistics> result = await client.getProgressStatistics(examSubjectId.toString());
|
|
if (result.code == RequestConfig.successCode) {
|
|
toUpState(setState, () => statisticsData = result.data!, mounted);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 获取分页数据
|
|
* getDataForPageData
|
|
*/
|
|
void getDataForPageData(EasyRefreshController controller, {bool isReFresh = false}) async {
|
|
RestClient client = await getClient();
|
|
|
|
BasePageData<ProgressItem>? results = await toRefreshDataWithPath(
|
|
controller,
|
|
api: client.getProgressByPage,
|
|
params: pageParams,
|
|
pahtVal: examSubjectId.toString(),
|
|
isReFresh: isReFresh,
|
|
context: context,
|
|
);
|
|
if (results != null && results.items.isNotEmpty) {
|
|
if (isReFresh) {
|
|
setState(() => listData = results.items);
|
|
} else {
|
|
setState(() => listData.addAll(results.items));
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
name = widget.name;
|
|
examSubjectId = widget.examSubjectId;
|
|
pageParams = ProgressPageParams(examSubjectId: examSubjectId, page: 1, limit: 10);
|
|
_refreshController = EasyRefreshController();
|
|
|
|
getDataForStatistics();
|
|
super.initState();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_refreshController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return AnnotatedRegion(
|
|
value: const SystemUiOverlayStyle(
|
|
statusBarColor: Colors.transparent,
|
|
systemNavigationBarIconBrightness: Brightness.light,
|
|
statusBarIconBrightness: Brightness.light,
|
|
statusBarBrightness: Brightness.dark,
|
|
),
|
|
child: Stack(
|
|
children: [
|
|
SizedBox(
|
|
height: double.infinity,
|
|
child: Column(
|
|
children: [
|
|
Container(
|
|
height: 200.h,
|
|
decoration: const BoxDecoration(
|
|
image: DecorationImage(
|
|
image: AssetImage('assets/images/personal_bgi.png'),
|
|
fit: BoxFit.cover,
|
|
),
|
|
),
|
|
),
|
|
Expanded(
|
|
child: Container(
|
|
color: const Color.fromRGBO(248, 248, 248, 1),
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
Scaffold(
|
|
backgroundColor: Colors.transparent,
|
|
appBar: PreferredSize(
|
|
preferredSize: Size.fromHeight(40.h),
|
|
child: AppBar(
|
|
title: quickText(
|
|
'$name进度',
|
|
size: 18.sp,
|
|
color: Colors.white,
|
|
),
|
|
elevation: 0,
|
|
backgroundColor: Colors.transparent,
|
|
),
|
|
),
|
|
body: EasyRefresh(
|
|
firstRefresh: true,
|
|
taskIndependence: true,
|
|
enableControlFinishLoad: true,
|
|
enableControlFinishRefresh: true,
|
|
controller: _refreshController,
|
|
onRefresh: () async => getDataForPageData(_refreshController, isReFresh: true),
|
|
onLoad: () async {
|
|
pageParams.page += 1;
|
|
getDataForPageData(_refreshController);
|
|
},
|
|
header: DeliveryHeader(),
|
|
footer: MaterialFooter(),
|
|
child: ListView(
|
|
padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 14.h),
|
|
children: [_StatisticsInfo(widget.name, statisticsData), ...listData.map((e) => _DataItem(e))],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// 统计情况
|
|
// ignore: must_be_immutable
|
|
class _StatisticsInfo extends StatelessWidget {
|
|
String name;
|
|
ProgressStatistics theData;
|
|
|
|
_StatisticsInfo(this.name, this.theData, {Key? key}) : super(key: key);
|
|
|
|
final TextStyle ts2 = TextStyle(
|
|
fontSize: 12.sp,
|
|
color: const Color.fromRGBO(148, 163, 182, 1),
|
|
);
|
|
|
|
final TextStyle ts1 = TextStyle(
|
|
fontSize: 18.sp,
|
|
color: const Color.fromRGBO(45, 56, 76, 1),
|
|
);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
TextStyle ts11 = TextStyle(
|
|
fontSize: 18.sp,
|
|
color: Theme.of(context).primaryColor,
|
|
);
|
|
|
|
double myAverage = theData.myAverage;
|
|
double overallAverage = theData.overallAverage;
|
|
|
|
double comparison = myAverage - overallAverage; // 比较情况
|
|
String imageUrl;
|
|
if (comparison > 0) {
|
|
imageUrl = 'assets/images/rise.png';
|
|
} else if (comparison < 0) {
|
|
imageUrl = 'assets/images/fall.png';
|
|
} else {
|
|
imageUrl = 'assets/images/equal.png';
|
|
}
|
|
Image comparisonImg = Image.asset(imageUrl, fit: BoxFit.cover, width: 10.w, height: 10.w);
|
|
|
|
return Container(
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h),
|
|
height: 194.h,
|
|
margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.all(Radius.circular(6.w)),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: const Color.fromRGBO(46, 91, 255, 0.1),
|
|
offset: Offset(6.w, 10.h), //阴影y轴偏移量
|
|
blurRadius: 14, //阴影模糊程度
|
|
spreadRadius: 0.5, //阴影扩散程度
|
|
)
|
|
],
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
name,
|
|
textAlign: TextAlign.left,
|
|
style: TextStyle(fontSize: 14.sp, color: const Color.fromRGBO(45, 56, 76, 1)),
|
|
),
|
|
Expanded(
|
|
child: Container(
|
|
margin: EdgeInsets.only(top: 18.h),
|
|
child: Row(
|
|
children: [
|
|
Stack(
|
|
alignment: const FractionalOffset(0.5, 0.5),
|
|
children: [
|
|
SizedBox(
|
|
width: 96.w,
|
|
height: 96.w,
|
|
child: theData.markingTotal == 0
|
|
? null
|
|
: CircularProgressIndicator(
|
|
backgroundColor: const Color.fromRGBO(217, 225, 255, 1),
|
|
valueColor: AlwaysStoppedAnimation(Theme.of(context).primaryColor),
|
|
value: theData.completionRate,
|
|
strokeWidth: 9.w),
|
|
),
|
|
Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
quickText(
|
|
'${theData.completionRateStr}%',
|
|
size: 20.sp,
|
|
color: Theme.of(context).primaryColor,
|
|
),
|
|
quickText(
|
|
'整体进度',
|
|
size: 10.sp,
|
|
color: const Color.fromRGBO(148, 163, 182, 1),
|
|
)
|
|
],
|
|
),
|
|
],
|
|
),
|
|
Expanded(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: [
|
|
Column(
|
|
children: [
|
|
Text('${theData.markingFinishedCount}', style: ts1),
|
|
Container(height: 3.h),
|
|
Text('已阅总量', style: ts2),
|
|
],
|
|
),
|
|
Column(
|
|
children: [
|
|
Text('${theData.markingUnfinishedCount}', style: ts11),
|
|
Container(height: 3.h),
|
|
Text('待阅总量', style: ts2),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: [
|
|
Column(
|
|
children: [
|
|
Text(overallAverage.toStringAsFixed(2), style: ts1),
|
|
Container(height: 3.h),
|
|
Text('整体均分', style: ts2),
|
|
],
|
|
),
|
|
Stack(
|
|
alignment: const FractionalOffset(1.7, 0.4),
|
|
children: [
|
|
Column(
|
|
children: [
|
|
Text(myAverage.toStringAsFixed(2), style: ts11),
|
|
Container(height: 3.h),
|
|
Text('我的平均分', style: ts2),
|
|
],
|
|
),
|
|
Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
comparisonImg,
|
|
Container(height: 1.h),
|
|
Text(
|
|
(overallAverage - myAverage).toStringAsFixed(2),
|
|
style: TextStyle(
|
|
fontSize: 9.sp,
|
|
color: const Color.fromRGBO(148, 163, 182, 1),
|
|
),
|
|
),
|
|
],
|
|
)
|
|
],
|
|
)
|
|
],
|
|
)
|
|
],
|
|
),
|
|
)
|
|
],
|
|
),
|
|
))
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// 数据单个详情
|
|
class _DataItem extends StatelessWidget {
|
|
ProgressItem item;
|
|
|
|
_DataItem(this.item, {Key? key}) : super(key: key);
|
|
GlobalKey _redKey = GlobalKey();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
height: 100.h,
|
|
margin: EdgeInsets.only(top: 12.h),
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.all(Radius.circular(6.w)),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: const Color.fromRGBO(46, 91, 255, 0.1),
|
|
offset: Offset(6.w, 4.h), //阴影y轴偏移量
|
|
blurRadius: 8, //阴影模糊程度
|
|
spreadRadius: 0.3, //阴影扩散程度
|
|
)
|
|
],
|
|
),
|
|
child: Column(
|
|
// crossAxisAlignment: C,
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Expanded(
|
|
child: Row(
|
|
children: [
|
|
Text(
|
|
'${item.teacherName}老师',
|
|
style: TextStyle(
|
|
color: const Color.fromRGBO(45, 56, 76, 1),
|
|
fontWeight: FontWeight.w700,
|
|
fontSize: 14.sp,
|
|
),
|
|
),
|
|
Container(
|
|
margin: EdgeInsets.only(left: 14.w),
|
|
child: Row(
|
|
children: [
|
|
Text(
|
|
'评阅均分:',
|
|
style: TextStyle(
|
|
color: const Color.fromRGBO(46, 91, 255, 1),
|
|
fontSize: 12.sp,
|
|
),
|
|
),
|
|
Text(
|
|
item.avgScore.toStringAsFixed(2),
|
|
style: TextStyle(
|
|
color: const Color.fromRGBO(46, 91, 255, 1),
|
|
fontSize: 12.sp,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
)
|
|
],
|
|
)),
|
|
Text(
|
|
item.schoolName,
|
|
style: TextStyle(
|
|
fontSize: 12.sp,
|
|
color: const Color.fromRGBO(148, 163, 182, 1),
|
|
),
|
|
)
|
|
],
|
|
),
|
|
Padding(
|
|
padding: EdgeInsets.only(bottom: 8.h),
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: LinearPercentIndicator(
|
|
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 0),
|
|
// width: MediaQuery.of(context).size.width - 50,
|
|
animation: true,
|
|
lineHeight: 10.h,
|
|
animationDuration: 2500,
|
|
percent: item.completionRate,
|
|
center: quickText(
|
|
'${item.completionRateStr}%',
|
|
size: 10.sp,
|
|
color: Colors.white,
|
|
),
|
|
// linearStrokeCap: LinearStrokeCap.butt,
|
|
progressColor: Theme.of(context).primaryColor,
|
|
backgroundColor: const Color.fromRGBO(219, 224, 243, 1),
|
|
barRadius: Radius.circular(10.h)),
|
|
),
|
|
Container(
|
|
margin: EdgeInsets.only(left: 14.w),
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
quickText(item.finishCount.toString(), size: 12.sp, color: Theme.of(context).primaryColor),
|
|
quickText('/', size: 12.sp, color: const Color.fromRGBO(148, 163, 182, 1)),
|
|
quickText(item.totalCount.toString(), size: 12.sp, color: const Color.fromRGBO(148, 163, 182, 1)),
|
|
],
|
|
),
|
|
)
|
|
],
|
|
),
|
|
)
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|