/
VoteService.java
347 lines (287 loc) · 12.1 KB
/
VoteService.java
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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
package com.softeng.dingtalk.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.softeng.dingtalk.controller.WebSocketController;
import com.softeng.dingtalk.api.MessageApi;
import com.softeng.dingtalk.entity.*;
import com.softeng.dingtalk.enums.Position;
import com.softeng.dingtalk.repository.*;
import com.softeng.dingtalk.vo.VoteVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author zhanyeye
* @description: 内部评审论文投票的相关业务逻辑
* @create 2/6/2020 5:30 PM
*/
@Service
@Transactional
@Slf4j
public class VoteService {
@Autowired
VoteRepository voteRepository;
@Autowired
VoteDetailRepository voteDetailRepository;
@Autowired
InternalPaperRepository internalPaperRepository;
@Autowired
PaperDetailRepository paperDetailRepository;
@Autowired
AcRecordRepository acRecordRepository;
@Autowired
NotifyService notifyService;
@Autowired
PerformanceService performanceService;
@Autowired
PaperService paperService;
@Autowired
UserRepository userRepository;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private ExternalPaperRepository externalPaperRepository;
@Autowired
MessageApi messageApi;
//--------------------------------------------
// 内部论文评审相关操作
//--------------------------------------------
/**
* 创建投票 (内部投票)
* 钉钉发送消息
* 同时清空清空未结束投票缓存
* @param voteVO
*/
@CacheEvict(value = "voting", allEntries = true)
public Vote createVote(VoteVO voteVO) {
// 判断投票是否已经创建过
if (voteRepository.isExisted(voteVO.getPaperid(), false) != 0) {
throw new ResponseStatusException(HttpStatus.CONFLICT, "慢了一步,投票已经被别人发起了");
}
Vote vote = new Vote(LocalDateTime.now() ,LocalDateTime.of(LocalDate.now(), voteVO.getEndTime()), voteVO.getPaperid());
voteRepository.save(vote);
internalPaperRepository.updatePaperVote(voteVO.getPaperid(), vote.getId());
// 发送投票信息
String title = internalPaperRepository.getPaperTitleById(voteVO.getPaperid());
List<String> namelist = paperDetailRepository.listPaperAuthor(voteVO.getPaperid());
StringBuilder markdown = new StringBuilder().append(" #### 投票 \n ##### 论文: ").append(title).append(" \n ##### 作者: ");
for (String name : namelist) {
markdown.append(name).append(", ");
}
markdown.append(" \n 截止时间: ").append(voteVO.getEndTime().toString());
String url = new StringBuilder().append("/paper/in-detail/").append(voteVO.getPaperid()).append("/vote").toString();
messageApi.sendActionCard("内部评审投票", markdown.toString(), "前往投票", url);
return voteRepository.refresh(vote);
}
/**
*
* @param now
* @return
*/
public List<Vote> listUpcomingVote(LocalDateTime now) {
return voteRepository.listUpcomingVote(now);
}
/**
* 查询没有结束的投票,但即将结束的投票
* 缓存未结束的投票,用于减少查询数据的次数,当创建新投票后要清空缓存
* @param now
* @return
*/
@Cacheable(value = "voting")
public List<Vote> listUnderwayVote(LocalDateTime now) {
return voteRepository.listClosingVote(now);
}
/**
* 更新投票的最终结果,投票截止后调用, 被定时器调用
* @param v
* @return
*/
@CacheEvict(value = "voting", allEntries = true)
public Vote updateVote(Vote v) {
log.debug("投票结果更新,清空缓存");
int accept = voteDetailRepository.getAcceptCnt(v.getId());
int total = voteDetailRepository.getCnt(v.getId());
v.setStatus(true);
v.setAccept(accept);
v.setTotal(total);
boolean result = accept > total - accept;
v.setResult(result);
voteRepository.save(v);
if (!v.isExternal()) {
// 如果是内部评审投票
if (result == false) {
internalPaperRepository.updatePaperResult(v.getPid(), InternalPaper.NOTPASS);
} else {
internalPaperRepository.updatePaperResult(v.getPid(), InternalPaper.REVIEWING);
}
}
Map map = Map.of("vid", v.getId(), "isEnd", true);
try {
WebSocketController.sendInfo(objectMapper.writeValueAsString(map));
} catch (IOException e) {
e.printStackTrace();
}
return v;
}
/**
* 用户投票
* @param vid
* @param uid
* @param voteDetail
* @return
*/
public Map poll(int vid, int uid, VoteDetail voteDetail) {
// 收到投票的时间
LocalDateTime now = LocalDateTime.now();
Vote vote = voteRepository.findById(vid).get();
// 如果是内部评审论文,判断投票人是否为论文作者
if (!vote.isExternal()) {
Set<Integer> authorids = paperService.listAuthorId(vote.getPid());
if (authorids.contains(Integer.valueOf(uid))) {
throw new ResponseStatusException(HttpStatus.CONFLICT, "论文作者不能参与投票!");
}
}
if (now.isBefore(vote.getEndTime())) {
// 投票未截止
voteDetailRepository.save(voteDetail);
} else {
// 投票已截止
throw new ResponseStatusException(HttpStatus.CONFLICT, "投票已经截止!");
}
// 返回当前的投票结果
List<String> acceptlist = voteDetailRepository.listAcceptNamelist(vid);
List<String> rejectlist = voteDetailRepository.listRejectNamelist(vid);
// accept 票数
int accept = acceptlist.size();
// reject 票数
int reject = rejectlist.size();
// 总投票数
int total = accept + reject;
return Map.of("vid", vid, "status", true,"accept", accept, "total", total, "reject", reject, "myresult", voteDetail.getResult(),"acceptnames",acceptlist,"rejectnames", rejectlist);
}
/**
* 投票还未结束,用户获取投票信息
* @param vid
* @param uid
* @return
*/
public Map getVotingDetail(int vid, int uid){
Boolean myresult = voteDetailRepository.getVoteDetail(vid, uid);
if (myresult != null) {
//用户已经投票,可以查看结果
List<String> acceptlist = voteDetailRepository.listAcceptNamelist(vid);
List<String> rejectlist = voteDetailRepository.listRejectNamelist(vid);
// accept 票数
int accept = acceptlist.size();
// reject 票数
int reject = rejectlist.size();
// 总投票数
int total = accept + reject;
return Map.of("vid", vid, "status", false,"accept", accept, "total", total, "reject", reject, "myresult", myresult, "acceptnames",acceptlist,"rejectnames", rejectlist);
} else {
//用户没有投票,不可以查看结果
return Map.of("vid", vid, "status", false);
}
}
/**
* 获取已经结束的投票信息
* @param vid
* @param uid
* @return
*/
public Map getVotedDetail(int vid, int uid, boolean isExternal) {
List<String> acceptlist = voteDetailRepository.listAcceptNamelist(vid);
List<String> rejectlist = voteDetailRepository.listRejectNamelist(vid);
// accept 票数
int accept = acceptlist.size();
// reject 票数
int reject = rejectlist.size();
// 总投票数
int total = accept + reject;
// 用户本人的投票情况:accept, reject, 未参与(null)
Boolean myresult = voteDetailRepository.getVoteDetail(vid, uid);
// 获取投票的截止时间
LocalDateTime endTime = voteRepository.getEndTimeByVid(vid);
// 未投票人员名单
// 1. 查询所有不是待定且在投票之前加入的用户用户的id,已经投票的用户的id,
Set<Integer> totalIds = userRepository.listStudentIdBeforeVoteTime(endTime);
Set<Integer> votedIds = voteDetailRepository.findVoteUserid(vid);
// 2. 减去所有投票用户和论文作者的id
totalIds.removeAll(votedIds);
if (isExternal == false) {
InternalPaper internalPaper = internalPaperRepository.findByVid(vid);
Set<Integer> authorids = paperService.listAuthorId(internalPaper.getId());
totalIds.removeAll(authorids);
}
//totalIds.removeAll(alumniids);
// 3. 通过为投票用户id集合去查询用户姓名
Set<String> unVoteNames = new HashSet<>();
if (totalIds.size() > 0) {
unVoteNames = userRepository.listNameByids(totalIds);
}
if (myresult == null) {
return Map.of("vid", vid, "status", true,"accept", accept, "total", total, "reject", reject, "acceptnames",acceptlist,"rejectnames", rejectlist, "unvotenames", unVoteNames);
} else {
return Map.of("vid", vid, "status", true,"accept", accept, "total", total, "reject", reject, "myresult", myresult, "acceptnames",acceptlist,"rejectnames", rejectlist, "unvotenames", unVoteNames);
}
}
/**
* 生成投票的ac记录
* @param title
* @param user
* @param isRight
* @param dateTime
* @return
*/
private AcRecord generateAcRecord(String title, User user, boolean isRight, LocalDateTime dateTime) {
return AcRecord.builder()
.user(user)
// 论文投票AC变化,对于硕士生是1分,对于博士生是2分
.ac((isRight ? 1 : -1) * (user.getPosition() == Position.POSTGRADUATE ? 1 : 2))
.classify(AcRecord.VOTE)
.reason((isRight ? "投票预测正确:" : "投票预测错误:") + title)
.createTime(dateTime)
.build();
}
/**
* 根据论文最终结果计算投票者的ac
* @param vote
* @param result
*/
public void computeVoteAc(Vote vote, boolean result, LocalDateTime dateTime) {
if (vote == null) throw new RuntimeException("未发起投票");
List<VoteDetail> voteDetails = voteDetailRepository.listByVid(vote.getId());
// 删除旧的 acRecord
List<AcRecord> oldAcRecords = Optional.ofNullable(voteDetails).orElse(new ArrayList<>()).stream()
.filter(x -> x.getAcRecord() != null)
.map(x -> x.getAcRecord())
.collect(Collectors.toList());
acRecordRepository.deleteAll(oldAcRecords);
Paper paper = vote.isExternal() ? externalPaperRepository.findByVid(vote.getId()) : internalPaperRepository.findByVid(vote.getId());
if (paper == null) throw new RuntimeException("投票对应的论文不存在,请联系开发者");
// 重新计算投票者的 acRecord
List<AcRecord> acRecords = new ArrayList<>();
voteDetails.forEach(vd -> {
AcRecord acRecord = generateAcRecord(paper.getTitle(), vd.getUser(), vd.getResult() == result, dateTime);
vd.setAcRecord(acRecord);
acRecords.add(acRecord);
});
// 将数据保存到数据库
acRecordRepository.saveAll(acRecords);
voteDetailRepository.saveAll(voteDetails);
// 发送消息
notifyService.voteAcMessage(vote.getId(), result);
// 计算助研金
voteDetails.forEach(vd -> performanceService.computeSalary(vd.getUser().getId() , dateTime.toLocalDate()));
}
}