Skip to content

Commit 13b8ff0

Browse files
authored
Merge pull request #36 from Pairman/patch-score
Feature: Cache scores list.
2 parents 20eb151 + 6ce2ff2 commit 13b8ff0

File tree

5 files changed

+165
-7
lines changed

5 files changed

+165
-7
lines changed

lib/model/xidian_ids/score.dart

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33

44
// ignore_for_file: non_constant_identifier_names
55

6+
import 'package:json_annotation/json_annotation.dart';
7+
8+
part 'score.g.dart';
9+
10+
@JsonSerializable(explicitToJson: true)
611
class Score {
712
int mark; // 编号,用于某种计算,从 0 开始
813
String name; // 学科名称
@@ -17,6 +22,7 @@ class Score {
1722
String? level; // 等级
1823
String? isPassedStr; //是否及格,null 没出分,1 通过 0 没有
1924
String? classID; // 教学班序列号
25+
2026
Score({
2127
required this.mark,
2228
required this.name,
@@ -107,8 +113,43 @@ class Score {
107113
}
108114
}
109115
}
116+
117+
factory Score.fromJson(Map<String, dynamic> json) {
118+
return Score(
119+
mark: json['mark'],
120+
name: json['name'],
121+
score: (json['score'] as num?)?.toDouble(),
122+
semesterCode: json['semesterCode'],
123+
credit: (json['credit'] as num).toDouble(),
124+
classStatus: json['classStatus'],
125+
classType: json['classType'],
126+
scoreStatus: json['scoreStatus'],
127+
scoreTypeCode: json['scoreTypeCode'],
128+
level: json['level'],
129+
isPassedStr: json['isPassedStr'],
130+
classID: json['classID'],
131+
);
132+
}
133+
134+
Map<String, dynamic> toJson() {
135+
return {
136+
'mark': mark,
137+
'name': name,
138+
'score': score,
139+
'semesterCode': semesterCode,
140+
'credit': credit,
141+
'classStatus': classStatus,
142+
'classType': classType,
143+
'scoreStatus': scoreStatus,
144+
'scoreTypeCode': scoreTypeCode,
145+
'level': level,
146+
'isPassedStr': isPassedStr,
147+
'classID': classID,
148+
};
149+
}
110150
}
111151

152+
112153
class ComposeDetail {
113154
String content;
114155
String ratio;

lib/model/xidian_ids/score.g.dart

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/page/score/score.dart

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import 'package:flutter/material.dart';
77
import 'package:watermeter/model/xidian_ids/score.dart';
88
import 'package:watermeter/page/public_widget/public_widget.dart';
9+
import 'package:watermeter/page/public_widget/toast.dart';
910
import 'package:watermeter/page/score/score_page.dart';
1011
import 'package:watermeter/page/score/score_state.dart';
1112
import 'package:watermeter/repository/xidian_ids/ehall_score_session.dart';
@@ -28,7 +29,16 @@ class _ScoreWindowState extends State<ScoreWindow> {
2829
);
2930
}
3031

31-
void dataInit() => scoreList = ScoreSession().getScore();
32+
void dataInit() {
33+
ScoreSession session = ScoreSession()
34+
scoreList = session.getScore();
35+
if (session.isScoreListCacheUsed) {
36+
showToast(
37+
context: context,
38+
msg: "已显示缓存成绩信息",
39+
);
40+
}
41+
}
3242

3343
@override
3444
void initState() {
@@ -71,4 +81,4 @@ class _ScoreWindowState extends State<ScoreWindow> {
7181
},
7282
);
7383
}
74-
}
84+
}

lib/page/setting/about_page/about_page.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ class AboutPage extends StatelessWidget {
6262
"开发:图书馆搜索功能",
6363
"https://github.com/NanCunChild",
6464
),
65+
Developer(
66+
"Pairman",
67+
"https://avatars.githubusercontent.com/u/18365163",
68+
"开发:成绩信息缓存功能",
69+
"https://github.com/ZCWzy",
70+
),
6571
Developer(
6672
"ReverierXu",
6773
"https://blog.woooo.tech/img/avatar.png",

lib/repository/xidian_ids/ehall_score_session.dart

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,20 @@
77
// ignore_for_file: non_constant_identifier_names
88

99
import 'dart:convert';
10+
import 'dart:io';
11+
1012
import 'package:watermeter/repository/preference.dart' as pref;
1113
import 'package:watermeter/model/xidian_ids/score.dart';
1214
import 'package:watermeter/repository/logger.dart';
15+
import 'package:watermeter/repository/network_session.dart';
1316
import 'package:watermeter/repository/xidian_ids/ehall_session.dart';
1417

1518
/// 考试成绩 4768574631264620
1619
class ScoreSession extends EhallSession {
20+
static const scoreListCacheName = "scores.json";
21+
late File file = File("${supportPath.path}/${scoreListCacheName}");
22+
bool isScoreListCacheUsed = false;
23+
1724
/// Must be called after [getScore]!
1825
/// If bug, just return dummy data.
1926
Future<List<ComposeDetail>> getDetail(
@@ -86,12 +93,61 @@ class ScoreSession extends EhallSession {
8693
}
8794
}
8895

96+
Future<List<Score>> loadScoreListCache() async {
97+
log.i(
98+
"[ScoreSession][loadScoreListCache] "
99+
"Path at ${supportPath.path}/${scoreListCacheName}.",
100+
);
101+
if (file.existsSync()) {
102+
final timeDiff = DateTime.now().difference(
103+
file.lastModifiedSync()
104+
).inHours;
105+
if (timeDiff < 6) {
106+
log.i(
107+
"[ScoreSession][loadScoreListCache] "
108+
"Cache file effective.",
109+
);
110+
List<dynamic> data = jsonDecode(file.readAsStringSync());
111+
return data.map(
112+
(s) => Score.fromJson(s as Map<String, dynamic>)
113+
).toList();
114+
}
115+
}
116+
log.i(
117+
"[ScoreSession][loadScoreListCache] "
118+
"Cache file non-existent or ineffective.",
119+
);
120+
return [];
121+
}
122+
123+
void dumpScoreListCache(List<Score> scores) {
124+
file.writeAsStringSync(
125+
jsonEncode(scores.map((s) => s.toJson()).toList()),
126+
);
127+
log.i(
128+
"[ScoreWindow][dumpScoreListCache] "
129+
"Dumped scoreList to ${supportPath.path}/${scoreListCacheName}.",
130+
);
131+
}
132+
89133
Future<List<Score>> getScore() async {
90134
List<Score> toReturn = [];
135+
/// Try retrieving cached scores first.
136+
isScoreListCacheUsed = false;
137+
toReturn = await loadScoreListCache();
138+
if (!toReturn.isEmpty) {
139+
log.i(
140+
"[ScoreSession][getScore] "
141+
"Loaded scores from cache.",
142+
);
143+
isScoreListCacheUsed = true;
144+
return toReturn;
145+
}
91146

92-
/// Get all scores here.
147+
/// Otherwise get fresh score data.
93148
log.i(
94-
"[ScoreSession] Start getting the score.",
149+
"[ScoreSession][getScore] "
150+
"Start getting score data.",
95151
);
96152
Map<String, dynamic> querySetting = {
97153
'name': 'SFYX',
@@ -101,7 +157,8 @@ class ScoreSession extends EhallSession {
101157
};
102158

103159
log.i(
104-
"[ScoreSession] Ready to login the system.",
160+
"[ScoreSession][getScore] "
161+
"Ready to log into the system.",
105162
);
106163
var firstPost = await useApp("4768574631264620");
107164
log.i(
@@ -110,7 +167,8 @@ class ScoreSession extends EhallSession {
110167
await dioEhall.get(firstPost);
111168

112169
log.i(
113-
"[ScoreSession] Getting the score data.",
170+
"[ScoreSession][getScore] "
171+
"Getting score data.",
114172
);
115173
var getData = await dioEhall.post(
116174
"https://ehall.xidian.edu.cn/jwapp/sys/cjcx/modules/cjcx/xscjcx.do",
@@ -123,7 +181,8 @@ class ScoreSession extends EhallSession {
123181
},
124182
).then((value) => value.data);
125183
log.i(
126-
"[ScoreSession] Dealing the score data.",
184+
"[ScoreSession][getScore] "
185+
"Dealing with the score data.",
127186
);
128187
if (getData['datas']['xscjcx']["extParams"]["code"] != 1) {
129188
throw GetScoreFailedException(
@@ -150,6 +209,11 @@ class ScoreSession extends EhallSession {
150209
));
151210
j++;
152211
}
212+
dumpScoreListCache(toReturn);
213+
log.i(
214+
"[ScoreSession][getScore] "
215+
"Cached the score data.",
216+
);
153217
return toReturn;
154218
}
155219
}

0 commit comments

Comments
 (0)