1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
|
package seu.se;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.PersistenceCreator;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@Node
@JsonInclude(JsonInclude.Include.NON_NULL)
public class TreeNode {
@Id
final private String nodeId;
final private String label;
@JsonIgnore
final private String content;
final private String relation;
@JsonIgnore
final private TreeNode father;
@JsonIgnore
private List<Exercise> exercises;
@JsonIgnore
private List<UserScorePair> userScores;
public static TreeNodeRepository tnRepo;
@Node
public static class UserScorePair {
@Id
private final String id;
private final String nodeId;
private final Long userId;
private List<Double> scores;
public interface MasteryLevel {
String Excellent = "完美";
String Good = "很好";
String Average = "一般";
String Bad = "差";
static String getMasteryLevel(double averageScore) {
if (averageScore > 95)
return Excellent;
else if (averageScore > 80)
return Good;
else if (averageScore > 60)
return Average;
else
return Bad;
}
}
public static class UserScoreSerializer extends StdSerializer<UserScorePair> {
public UserScoreSerializer() {
this(null);
}
public UserScoreSerializer(Class<UserScorePair> t) {
super(t);
}
@Override
public void serialize(UserScorePair value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeStartObject();
gen.writeStringField("nodeId", value.nodeId);
var avg = value.getAverageScore();
gen.writeNumberField("averageScore", avg);
gen.writeNumberField("lastScore", value.getLastScore());
gen.writeStringField("masteryLevel", MasteryLevel.getMasteryLevel(avg));
gen.writeEndObject();
}
}
public UserScorePair(String nodeId, Long userId, List<Double> scores) {
this(String.format("%s.%d", nodeId, userId), nodeId, userId, scores);
}
@Autowired
@PersistenceCreator
public UserScorePair(String id, String nodeId, Long userId, List<Double> scores) {
this.id = id;
this.nodeId = nodeId;
this.userId = userId;
this.scores = scores;
}
public String getId() {
return id;
}
public String getNodeId() {
return nodeId;
}
public Long getUserId() {
return userId;
}
public List<Double> getScores() {
return scores;
}
public Double getLastScore() {
return scores.getLast();
}
public Double getAverageScore() {
Double sum = 0.0;
for (var i : scores)
sum += i;
return scores.isEmpty() ? sum : sum / scores.size();
}
public void setScores(List<Double> scores) {
this.scores = scores;
}
}
// MUST only be called during deserialization!!
@JsonCreator
public TreeNode(@JsonProperty("nodeId") String nodeId, @JsonProperty("label") String label, @JsonProperty("content") String content, @JsonProperty("relation") String relation, @JsonProperty("fatherId") String fatherId, @JsonProperty("exercises") List<Exercise> exercises) {
this(nodeId, label, content, relation, tnRepo.findByNodeId(fatherId), exercises, new ArrayList<>());
}
public TreeNode(String nodeId, String label, String content, String relation, TreeNode father, List<Exercise> exercises) {
this(nodeId, label, content, relation, father, exercises, new ArrayList<>());
}
@Autowired
@PersistenceCreator
public TreeNode(String nodeId, String label, String content, String relation, TreeNode father, List<Exercise> exercises, List<UserScorePair> userScores) {
this.nodeId = nodeId;
this.label = label;
this.content = content;
this.relation = relation;
this.father = father;
this.exercises = exercises;
this.userScores = userScores;
}
public String getLabel() {
return label;
}
public String getNodeId() {
return nodeId;
}
public String getContent() {
return content;
}
public TreeNode getFather() {
return father;
}
public String getRelation() {
return relation;
}
public List<Exercise> getExercises() {
return exercises;
}
public void setExercises(List<Exercise> exercises) {
this.exercises = exercises;
}
public List<UserScorePair> getUserScores() {
return userScores;
}
public UserScorePair getUserScorePair(Long userId, String nodeId) {
var usp = userScores.stream().filter(e -> Objects.equals(e.getUserId(), userId) && e.getNodeId().equals(nodeId)).findFirst();
return usp.orElse(null);
}
public void setUserScores(List<UserScorePair> userScores) {
this.userScores = userScores;
}
public int getLevel() {
var tmp = this;
var level = 1;
while (tmp.father != null) {
tmp = tmp.father;
level++;
}
return level;
}
public Set<TreeNode> getChildren(List<TreeNode> nodes) {
var children = new HashSet<TreeNode>();
for (var n : nodes) {
if (n.getFather() == this) {
children.add(n);
}
}
return children;
}
}
|