丰富前端操作,增加POJ的vjudge判题
This commit is contained in:
parent
270d10d96b
commit
8329f0d420
|
@ -85,6 +85,7 @@ docker ps # 查看当前运行的容器状态
|
||||||
| 2021-06-08 | 添加后台i18n,路由懒加载 | Himit_ZH |
|
| 2021-06-08 | 添加后台i18n,路由懒加载 | Himit_ZH |
|
||||||
| 2021-06-12 | 完善比赛赛制,具体请看在线文档 | Himit_ZH |
|
| 2021-06-12 | 完善比赛赛制,具体请看在线文档 | Himit_ZH |
|
||||||
| 2021-06-14 | 完善后台管理员权限控制,恢复CF的vjudge判题 | Himit_ZH |
|
| 2021-06-14 | 完善后台管理员权限控制,恢复CF的vjudge判题 | Himit_ZH |
|
||||||
|
| 2021-06-25 | 丰富前端操作,增加POJ的vjudge判题 | Himit_ZH |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -142,6 +142,7 @@ problem表
|
||||||
| open_case_result | boolean | | 是否默认开启该题目的测试样例结果查看 |
|
| open_case_result | boolean | | 是否默认开启该题目的测试样例结果查看 |
|
||||||
| caseVersion | String | | 题目测试数据的版本号 |
|
| caseVersion | String | | 题目测试数据的版本号 |
|
||||||
| is_upload_case | boolean | | 是否是上传zip评测数据的 |
|
| is_upload_case | boolean | | 是否是上传zip评测数据的 |
|
||||||
|
| modified_user | String | | 最新修改题目的用户 |
|
||||||
| gmt_create | datetime | | 创建时间 |
|
| gmt_create | datetime | | 创建时间 |
|
||||||
| gmt_modified | datetime | | 修改时间 |
|
| gmt_modified | datetime | | 修改时间 |
|
||||||
|
|
||||||
|
@ -529,6 +530,7 @@ discussion表
|
||||||
| view_num | int | | 浏览数量 |
|
| view_num | int | | 浏览数量 |
|
||||||
| like_num | int | | 点赞数量 |
|
| like_num | int | | 点赞数量 |
|
||||||
| top_priority | boolean | | 优先级,是否置顶 |
|
| top_priority | boolean | | 优先级,是否置顶 |
|
||||||
|
| comment_num | int | | 评论数量 |
|
||||||
| status | int | | 是否封禁或逻辑删除该讨论 |
|
| status | int | | 是否封禁或逻辑删除该讨论 |
|
||||||
| gmt_create | datetime | | 创建时间 |
|
| gmt_create | datetime | | 创建时间 |
|
||||||
| gmt_modified | datetime | | 修改时间 |
|
| gmt_modified | datetime | | 修改时间 |
|
||||||
|
|
|
@ -126,6 +126,12 @@
|
||||||
<version>5.3.3</version>
|
<version>5.3.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.vdurmont</groupId>
|
||||||
|
<artifactId>emoji-java</artifactId>
|
||||||
|
<version>4.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!--redis整合-->
|
<!--redis整合-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
|
|
@ -105,6 +105,12 @@ public class StartupRunner implements CommandLineRunner {
|
||||||
@Value("${CF_ACCOUNT_PASSWORD_LIST:}")
|
@Value("${CF_ACCOUNT_PASSWORD_LIST:}")
|
||||||
private List<String> cfPasswordList;
|
private List<String> cfPasswordList;
|
||||||
|
|
||||||
|
@Value("${POJ_ACCOUNT_USERNAME_LIST:}")
|
||||||
|
private List<String> pojUsernameList;
|
||||||
|
|
||||||
|
@Value("${POJ_ACCOUNT_PASSWORD_LIST:}")
|
||||||
|
private List<String> pojPasswordList;
|
||||||
|
|
||||||
@Value("${spring.profiles.active}")
|
@Value("${spring.profiles.active}")
|
||||||
private String profile;
|
private String profile;
|
||||||
|
|
||||||
|
@ -151,6 +157,10 @@ public class StartupRunner implements CommandLineRunner {
|
||||||
|
|
||||||
configVo.setCfUsernameList(cfUsernameList);
|
configVo.setCfUsernameList(cfUsernameList);
|
||||||
configVo.setCfPasswordList(cfPasswordList);
|
configVo.setCfPasswordList(cfPasswordList);
|
||||||
|
|
||||||
|
configVo.setPojUsernameList(pojUsernameList);
|
||||||
|
configVo.setPojPasswordList(pojPasswordList);
|
||||||
|
|
||||||
configService.sendNewConfigToNacos();
|
configService.sendNewConfigToNacos();
|
||||||
|
|
||||||
if (openRemoteJudge.equals("true")) {
|
if (openRemoteJudge.equals("true")) {
|
||||||
|
@ -203,6 +213,22 @@ public class StartupRunner implements CommandLineRunner {
|
||||||
log.error("Codeforces账号添加失败------------>{}", "请检查配置文件,然后重新启动!");
|
log.error("Codeforces账号添加失败------------>{}", "请检查配置文件,然后重新启动!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<RemoteJudgeAccount> pojRemoteAccountList = new LinkedList<>();
|
||||||
|
for (int i = 0; i < pojUsernameList.size(); i++) {
|
||||||
|
pojRemoteAccountList.add(new RemoteJudgeAccount()
|
||||||
|
.setUsername(pojUsernameList.get(i))
|
||||||
|
.setPassword(pojPasswordList.get(i))
|
||||||
|
.setStatus(true)
|
||||||
|
.setVersion(0L)
|
||||||
|
.setOj("POJ"));
|
||||||
|
}
|
||||||
|
if (pojRemoteAccountList.size()>0) {
|
||||||
|
boolean addPOJOk = remoteJudgeAccountService.saveOrUpdateBatch(pojRemoteAccountList);
|
||||||
|
if (!addPOJOk) {
|
||||||
|
log.error("POJ账号添加失败------------>{}", "请检查配置文件,然后重新启动!");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -326,7 +326,11 @@ public class AdminContestController {
|
||||||
if (problem != null && problem.getId().longValue() != problemDto.getProblem().getId()) {
|
if (problem != null && problem.getId().longValue() != problemDto.getProblem().getId()) {
|
||||||
return CommonResult.errorResponse("当前的Problem ID 已被使用,请重新更换新的!", CommonResult.STATUS_FAIL);
|
return CommonResult.errorResponse("当前的Problem ID 已被使用,请重新更换新的!", CommonResult.STATUS_FAIL);
|
||||||
}
|
}
|
||||||
|
// 获取当前登录的用户
|
||||||
|
HttpSession session = request.getSession();
|
||||||
|
UserRolesVo userRolesVo = (UserRolesVo) session.getAttribute("userInfo");
|
||||||
|
// 记录修改题目的用户
|
||||||
|
problemDto.getProblem().setModifiedUser(userRolesVo.getUsername());
|
||||||
boolean result = problemService.adminUpdateProblem(problemDto);
|
boolean result = problemService.adminUpdateProblem(problemDto);
|
||||||
if (result) { // 更新成功
|
if (result) { // 更新成功
|
||||||
return CommonResult.successResponse(null, "修改成功!");
|
return CommonResult.successResponse(null, "修改成功!");
|
||||||
|
|
|
@ -144,7 +144,7 @@ public class AdminProblemController {
|
||||||
@RequiresAuthentication
|
@RequiresAuthentication
|
||||||
@RequiresRoles(value = {"root", "admin", "problem_admin"}, logical = Logical.OR)
|
@RequiresRoles(value = {"root", "admin", "problem_admin"}, logical = Logical.OR)
|
||||||
@Transactional
|
@Transactional
|
||||||
public CommonResult updateProblem(@RequestBody ProblemDto problemDto) {
|
public CommonResult updateProblem(@RequestBody ProblemDto problemDto, HttpServletRequest request) {
|
||||||
|
|
||||||
QueryWrapper<Problem> queryWrapper = new QueryWrapper<>();
|
QueryWrapper<Problem> queryWrapper = new QueryWrapper<>();
|
||||||
queryWrapper.eq("problem_id", problemDto.getProblem().getProblemId().toUpperCase());
|
queryWrapper.eq("problem_id", problemDto.getProblem().getProblemId().toUpperCase());
|
||||||
|
@ -154,6 +154,11 @@ public class AdminProblemController {
|
||||||
if (problem != null && problem.getId().longValue() != problemDto.getProblem().getId()) {
|
if (problem != null && problem.getId().longValue() != problemDto.getProblem().getId()) {
|
||||||
return CommonResult.errorResponse("当前的Problem ID 已被使用,请重新更换新的!", CommonResult.STATUS_FAIL);
|
return CommonResult.errorResponse("当前的Problem ID 已被使用,请重新更换新的!", CommonResult.STATUS_FAIL);
|
||||||
}
|
}
|
||||||
|
// 获取当前登录的用户
|
||||||
|
HttpSession session = request.getSession();
|
||||||
|
UserRolesVo userRolesVo = (UserRolesVo) session.getAttribute("userInfo");
|
||||||
|
// 记录修改题目的用户
|
||||||
|
problemDto.getProblem().setModifiedUser(userRolesVo.getUsername());
|
||||||
|
|
||||||
boolean result = problemService.adminUpdateProblem(problemDto);
|
boolean result = problemService.adminUpdateProblem(problemDto);
|
||||||
if (result) { // 更新成功
|
if (result) { // 更新成功
|
||||||
|
|
|
@ -12,13 +12,16 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import top.hcode.hoj.common.result.CommonResult;
|
import top.hcode.hoj.common.result.CommonResult;
|
||||||
|
import top.hcode.hoj.pojo.dto.ReplyDto;
|
||||||
import top.hcode.hoj.pojo.entity.Comment;
|
import top.hcode.hoj.pojo.entity.Comment;
|
||||||
import top.hcode.hoj.pojo.entity.CommentLike;
|
import top.hcode.hoj.pojo.entity.CommentLike;
|
||||||
|
import top.hcode.hoj.pojo.entity.Discussion;
|
||||||
import top.hcode.hoj.pojo.entity.Reply;
|
import top.hcode.hoj.pojo.entity.Reply;
|
||||||
import top.hcode.hoj.pojo.vo.CommentsVo;
|
import top.hcode.hoj.pojo.vo.CommentsVo;
|
||||||
import top.hcode.hoj.pojo.vo.UserRolesVo;
|
import top.hcode.hoj.pojo.vo.UserRolesVo;
|
||||||
import top.hcode.hoj.service.impl.CommentLikeServiceImpl;
|
import top.hcode.hoj.service.impl.CommentLikeServiceImpl;
|
||||||
import top.hcode.hoj.service.impl.CommentServiceImpl;
|
import top.hcode.hoj.service.impl.CommentServiceImpl;
|
||||||
|
import top.hcode.hoj.service.impl.DiscussionServiceImpl;
|
||||||
import top.hcode.hoj.service.impl.ReplyServiceImpl;
|
import top.hcode.hoj.service.impl.ReplyServiceImpl;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -45,6 +48,9 @@ public class CommentController {
|
||||||
@Autowired
|
@Autowired
|
||||||
private ReplyServiceImpl replyService;
|
private ReplyServiceImpl replyService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DiscussionServiceImpl discussionService;
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/comments")
|
@GetMapping("/comments")
|
||||||
public CommonResult getComments(@RequestParam(value = "cid", required = false) Long cid,
|
public CommonResult getComments(@RequestParam(value = "cid", required = false) Long cid,
|
||||||
|
@ -126,6 +132,13 @@ public class CommentController {
|
||||||
commentsVo.setLikeNum(0);
|
commentsVo.setLikeNum(0);
|
||||||
commentsVo.setGmtCreate(comment.getGmtCreate());
|
commentsVo.setGmtCreate(comment.getGmtCreate());
|
||||||
commentsVo.setReplyList(new LinkedList<>());
|
commentsVo.setReplyList(new LinkedList<>());
|
||||||
|
// 如果是讨论区的回复,发布成功需要添加统计该讨论的回复数
|
||||||
|
if (comment.getDid() != null) {
|
||||||
|
UpdateWrapper<Discussion> discussionUpdateWrapper = new UpdateWrapper<>();
|
||||||
|
discussionUpdateWrapper.eq("id", comment.getDid())
|
||||||
|
.setSql("comment_num=comment_num+1");
|
||||||
|
discussionService.update(discussionUpdateWrapper);
|
||||||
|
}
|
||||||
return CommonResult.successResponse(commentsVo, "评论成功");
|
return CommonResult.successResponse(commentsVo, "评论成功");
|
||||||
} else {
|
} else {
|
||||||
return CommonResult.errorResponse("评论失败,请重新尝试!");
|
return CommonResult.errorResponse("评论失败,请重新尝试!");
|
||||||
|
@ -151,6 +164,13 @@ public class CommentController {
|
||||||
replyService.remove(new UpdateWrapper<Reply>().eq("comment_id", comment.getId()));
|
replyService.remove(new UpdateWrapper<Reply>().eq("comment_id", comment.getId()));
|
||||||
|
|
||||||
if (isDeleteComment) {
|
if (isDeleteComment) {
|
||||||
|
// 如果是讨论区的回复,删除成功需要减少统计该讨论的回复数
|
||||||
|
if (comment.getDid() != null) {
|
||||||
|
UpdateWrapper<Discussion> discussionUpdateWrapper = new UpdateWrapper<>();
|
||||||
|
discussionUpdateWrapper.eq("id", comment.getDid())
|
||||||
|
.setSql("comment_num=comment_num-1");
|
||||||
|
discussionService.update(discussionUpdateWrapper);
|
||||||
|
}
|
||||||
return CommonResult.successResponse(null, "删除成功");
|
return CommonResult.successResponse(null, "删除成功");
|
||||||
} else {
|
} else {
|
||||||
return CommonResult.errorResponse("删除失败,请重新尝试");
|
return CommonResult.errorResponse("删除失败,请重新尝试");
|
||||||
|
@ -222,11 +242,11 @@ public class CommentController {
|
||||||
@PostMapping("/reply")
|
@PostMapping("/reply")
|
||||||
@RequiresPermissions("reply_add")
|
@RequiresPermissions("reply_add")
|
||||||
@RequiresAuthentication
|
@RequiresAuthentication
|
||||||
public CommonResult addReply(@RequestBody Reply reply, HttpServletRequest request) {
|
public CommonResult addReply(@RequestBody ReplyDto replyDto, HttpServletRequest request) {
|
||||||
// 获取当前登录的用户
|
// 获取当前登录的用户
|
||||||
HttpSession session = request.getSession();
|
HttpSession session = request.getSession();
|
||||||
UserRolesVo userRolesVo = (UserRolesVo) session.getAttribute("userInfo");
|
UserRolesVo userRolesVo = (UserRolesVo) session.getAttribute("userInfo");
|
||||||
|
Reply reply = replyDto.getReply();
|
||||||
reply.setFromAvatar(userRolesVo.getAvatar())
|
reply.setFromAvatar(userRolesVo.getAvatar())
|
||||||
.setFromName(userRolesVo.getUsername())
|
.setFromName(userRolesVo.getUsername())
|
||||||
.setFromUid(userRolesVo.getUid());
|
.setFromUid(userRolesVo.getUid());
|
||||||
|
@ -244,6 +264,13 @@ public class CommentController {
|
||||||
boolean isOk = replyService.saveOrUpdate(reply);
|
boolean isOk = replyService.saveOrUpdate(reply);
|
||||||
|
|
||||||
if (isOk) {
|
if (isOk) {
|
||||||
|
// 如果是讨论区的回复,发布成功需要增加统计该讨论的回复数
|
||||||
|
if (replyDto.getDid() != null) {
|
||||||
|
UpdateWrapper<Discussion> discussionUpdateWrapper = new UpdateWrapper<>();
|
||||||
|
discussionUpdateWrapper.eq("id", replyDto.getDid())
|
||||||
|
.setSql("comment_num=comment_num+1");
|
||||||
|
discussionService.update(discussionUpdateWrapper);
|
||||||
|
}
|
||||||
return CommonResult.successResponse(reply, "评论成功");
|
return CommonResult.successResponse(reply, "评论成功");
|
||||||
} else {
|
} else {
|
||||||
return CommonResult.errorResponse("评论失败,请重新尝试!");
|
return CommonResult.errorResponse("评论失败,请重新尝试!");
|
||||||
|
@ -252,19 +279,24 @@ public class CommentController {
|
||||||
|
|
||||||
@DeleteMapping("/reply")
|
@DeleteMapping("/reply")
|
||||||
@RequiresAuthentication
|
@RequiresAuthentication
|
||||||
public CommonResult deleteReply(@RequestBody Reply reply, HttpServletRequest request) {
|
public CommonResult deleteReply(@RequestBody ReplyDto replyDto, HttpServletRequest request) {
|
||||||
// 获取当前登录的用户
|
// 获取当前登录的用户
|
||||||
HttpSession session = request.getSession();
|
HttpSession session = request.getSession();
|
||||||
UserRolesVo userRolesVo = (UserRolesVo) session.getAttribute("userInfo");
|
UserRolesVo userRolesVo = (UserRolesVo) session.getAttribute("userInfo");
|
||||||
|
Reply reply = replyDto.getReply();
|
||||||
// 如果不是评论本人 或者不是管理员 无权限删除该评论
|
// 如果不是评论本人 或者不是管理员 无权限删除该评论
|
||||||
if (reply.getFromUid().equals(userRolesVo.getUid()) || SecurityUtils.getSubject().hasRole("root")
|
if (reply.getFromUid().equals(userRolesVo.getUid()) || SecurityUtils.getSubject().hasRole("root")
|
||||||
|| SecurityUtils.getSubject().hasRole("admin") || SecurityUtils.getSubject().hasRole("problem_admin")) {
|
|| SecurityUtils.getSubject().hasRole("admin") || SecurityUtils.getSubject().hasRole("problem_admin")) {
|
||||||
|
|
||||||
// 删除该数据
|
// 删除该数据
|
||||||
boolean isOk = replyService.removeById(reply.getId());
|
boolean isOk = replyService.removeById(reply.getId());
|
||||||
|
|
||||||
if (isOk) {
|
if (isOk) {
|
||||||
|
// 如果是讨论区的回复,删除成功需要减少统计该讨论的回复数
|
||||||
|
if (replyDto.getDid() != null) {
|
||||||
|
UpdateWrapper<Discussion> discussionUpdateWrapper = new UpdateWrapper<>();
|
||||||
|
discussionUpdateWrapper.eq("id", replyDto.getDid())
|
||||||
|
.setSql("comment_num=comment_num-1");
|
||||||
|
discussionService.update(discussionUpdateWrapper);
|
||||||
|
}
|
||||||
return CommonResult.successResponse(null, "删除成功");
|
return CommonResult.successResponse(null, "删除成功");
|
||||||
} else {
|
} else {
|
||||||
return CommonResult.errorResponse("删除失败,请重新尝试");
|
return CommonResult.errorResponse("删除失败,请重新尝试");
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package top.hcode.hoj.crawler.problem;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ReUtil;
|
||||||
|
import org.jsoup.Connection;
|
||||||
|
import org.jsoup.nodes.Document;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import top.hcode.hoj.pojo.entity.Problem;
|
||||||
|
import top.hcode.hoj.utils.JsoupUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: Himit_ZH
|
||||||
|
* @Date: 2021/6/24 23:27
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
public class POJProblemStrategy extends ProblemStrategy {
|
||||||
|
|
||||||
|
public static final String JUDGE_NAME = "POJ";
|
||||||
|
public static final String HOST = "http://poj.org";
|
||||||
|
public static final String PROBLEM_URL = "/problem?id=%s";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RemoteProblemInfo getProblemInfo(String problemId, String author) throws Exception {
|
||||||
|
|
||||||
|
// 验证题号是否符合规范
|
||||||
|
Assert.isTrue(problemId.matches("[1-9]\\d*"), "POJ题号格式错误!");
|
||||||
|
Problem info = new Problem();
|
||||||
|
String url = HOST + String.format(PROBLEM_URL, problemId);
|
||||||
|
Connection connection = JsoupUtils.getConnectionFromUrl(url, null, null);
|
||||||
|
Document document = JsoupUtils.getDocument(connection, null);
|
||||||
|
String html = document.html();
|
||||||
|
html = html.replaceAll("<br>", "\n");
|
||||||
|
info.setProblemId(JUDGE_NAME + "-" + problemId);
|
||||||
|
info.setTitle(ReUtil.get("<title>\\d{3,} -- ([\\s\\S]*?)</title>", html, 1).trim());
|
||||||
|
info.setTimeLimit(Integer.parseInt(ReUtil.get("<b>Time Limit:</b> (\\d{3,})MS</td>", html, 1)));
|
||||||
|
info.setMemoryLimit(Integer.parseInt(ReUtil.get("<b>Memory Limit:</b> (\\d{2,})K</td>", html, 1)) / 1024);
|
||||||
|
info.setDescription(ReUtil.get("<p class=\"pst\">Description</p><div class=.*?>([\\s\\S]*?)</div><p class=\"pst\">", html, 1)
|
||||||
|
.replaceAll("src=\"../../", "src=\"" + HOST + "/"));
|
||||||
|
|
||||||
|
info.setInput(ReUtil.get("<p class=\"pst\">Input</p><div class=.*?>([\\s\\S]*?)</div><p class=\"pst\">", html, 1));
|
||||||
|
info.setOutput(ReUtil.get("<p class=\"pst\">Output</p><div class=.*?>([\\s\\S]*?)</div><p class=\"pst\">", html, 1));
|
||||||
|
StringBuilder sb = new StringBuilder("<input>");
|
||||||
|
sb.append(ReUtil.get("<p class=\"pst\">Sample Input</p><pre class=.*?>([\\s\\S]*?)</pre><p class=\"pst\">", html, 1));
|
||||||
|
sb.append("</input><output>");
|
||||||
|
sb.append(ReUtil.get("<p class=\"pst\">Sample Output</p><pre class=.*?>([\\s\\S]*?)</pre><p class=\"pst\">", html, 1))
|
||||||
|
.append("</output>");
|
||||||
|
info.setExamples(sb.toString());
|
||||||
|
info.setHint(ReUtil.get("<p class=.*?>Hint</p><div class=.*?>([\\s\\S]*?)</div><p class=\"pst\">", html, 1));
|
||||||
|
info.setIsRemote(true);
|
||||||
|
info.setSource(String.format("<a style='color:#1A5CC8' href='http://poj.org/problem?id=%s'>%s</a>", problemId, JUDGE_NAME + "-" + problemId));
|
||||||
|
info.setType(0)
|
||||||
|
.setAuth(1)
|
||||||
|
.setAuthor(author)
|
||||||
|
.setOpenCaseResult(false)
|
||||||
|
.setIsRemoveEndBlank(false)
|
||||||
|
.setDifficulty(1); // 默认为简单
|
||||||
|
return new RemoteProblemInfo().setProblem(info).setTagList(null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package top.hcode.hoj.pojo.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
import top.hcode.hoj.pojo.entity.Reply;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: Himit_ZH
|
||||||
|
* @Date: 2021/6/24 17:00
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class ReplyDto {
|
||||||
|
|
||||||
|
private Reply reply;
|
||||||
|
|
||||||
|
private Long did;
|
||||||
|
}
|
|
@ -119,4 +119,10 @@ public class ConfigVo {
|
||||||
@Value("${hoj.cf.account.password:}")
|
@Value("${hoj.cf.account.password:}")
|
||||||
private List<String> cfPasswordList;
|
private List<String> cfPasswordList;
|
||||||
|
|
||||||
|
@Value("${hoj.poj.account.username:}")
|
||||||
|
private List<String> pojUsernameList;
|
||||||
|
|
||||||
|
@Value("${hoj.poj.account.password:}")
|
||||||
|
private List<String> pojPasswordList;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.DigestUtils;
|
import org.springframework.util.DigestUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.yaml.snakeyaml.Yaml;
|
import org.yaml.snakeyaml.Yaml;
|
||||||
import top.hcode.hoj.crawler.problem.CFProblemStrategy;
|
import top.hcode.hoj.crawler.problem.*;
|
||||||
import top.hcode.hoj.crawler.problem.HDUProblemStrategy;
|
|
||||||
import top.hcode.hoj.crawler.problem.ProblemContext;
|
|
||||||
import top.hcode.hoj.crawler.problem.ProblemStrategy;
|
|
||||||
import top.hcode.hoj.pojo.dto.ProblemDto;
|
import top.hcode.hoj.pojo.dto.ProblemDto;
|
||||||
import top.hcode.hoj.pojo.entity.*;
|
import top.hcode.hoj.pojo.entity.*;
|
||||||
import top.hcode.hoj.pojo.vo.ImportProblemVo;
|
import top.hcode.hoj.pojo.vo.ImportProblemVo;
|
||||||
|
@ -544,6 +541,9 @@ public class ProblemServiceImpl extends ServiceImpl<ProblemMapper, Problem> impl
|
||||||
case "CF":
|
case "CF":
|
||||||
problemStrategy = new CFProblemStrategy();
|
problemStrategy = new CFProblemStrategy();
|
||||||
break;
|
break;
|
||||||
|
case "POJ":
|
||||||
|
problemStrategy = new POJProblemStrategy();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception("未知的OJ的名字,暂时不支持!");
|
throw new Exception("未知的OJ的名字,暂时不支持!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,11 @@ public class ConfigUtils {
|
||||||
" cf:\n" +
|
" cf:\n" +
|
||||||
" account:\n" +
|
" account:\n" +
|
||||||
" username: " + listToStr(configVo.getCfUsernameList()) + "\n" +
|
" username: " + listToStr(configVo.getCfUsernameList()) + "\n" +
|
||||||
" password: " + listToStr(configVo.getCfPasswordList());
|
" password: " + listToStr(configVo.getCfPasswordList()) + "\n" +
|
||||||
|
" poj:\n" +
|
||||||
|
" account:\n" +
|
||||||
|
" username: " + listToStr(configVo.getPojUsernameList()) + "\n" +
|
||||||
|
" password: " + listToStr(configVo.getPojPasswordList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String listToStr(List<String> list) {
|
private String listToStr(List<String> list) {
|
||||||
|
|
|
@ -58,7 +58,8 @@ public class Constants {
|
||||||
|
|
||||||
public enum RemoteOJ {
|
public enum RemoteOJ {
|
||||||
HDU("HDU"),
|
HDU("HDU"),
|
||||||
CODEFORCES("CF");
|
CODEFORCES("CF"),
|
||||||
|
POJ("POJ");
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,7 @@ public class RemoteJudgeGetResult {
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void sendTask(String remoteJudge, String username, Long submitId, String uid,
|
public void sendTask(String remoteJudge, String username, Long submitId, String uid,
|
||||||
Long cid, Long pid, Long resultSubmitId, String token,
|
Long cid, Long pid, Long resultSubmitId, String cookies) {
|
||||||
HashMap<String, String> cookies) {
|
|
||||||
|
|
||||||
RemoteJudgeStrategy remoteJudgeStrategy = RemoteJudgeFactory.selectJudge(remoteJudge);
|
RemoteJudgeStrategy remoteJudgeStrategy = RemoteJudgeFactory.selectJudge(remoteJudge);
|
||||||
|
|
||||||
|
@ -47,7 +46,7 @@ public class RemoteJudgeGetResult {
|
||||||
public void run() {
|
public void run() {
|
||||||
count.getAndIncrement();
|
count.getAndIncrement();
|
||||||
try {
|
try {
|
||||||
Map<String, Object> result = remoteJudgeStrategy.result(resultSubmitId, username, token, cookies);
|
Map<String, Object> result = remoteJudgeStrategy.result(resultSubmitId, username, cookies);
|
||||||
Integer status = (Integer) result.getOrDefault("status", Constants.Judge.STATUS_SYSTEM_ERROR.getStatus());
|
Integer status = (Integer) result.getOrDefault("status", Constants.Judge.STATUS_SYSTEM_ERROR.getStatus());
|
||||||
if (status.intValue() != Constants.Judge.STATUS_PENDING.getStatus() &&
|
if (status.intValue() != Constants.Judge.STATUS_PENDING.getStatus() &&
|
||||||
status.intValue() != Constants.Judge.STATUS_JUDGING.getStatus()) {
|
status.intValue() != Constants.Judge.STATUS_JUDGING.getStatus()) {
|
||||||
|
|
|
@ -87,17 +87,16 @@ public class RemoteJudgeToSubmit {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提交成功顺便更新状态为-->STATUS_JUDGING 判题中...
|
// 提交成功顺便更新状态为-->STATUS_PENDING 等待中...
|
||||||
judgeService.updateById(new Judge()
|
judgeService.updateById(new Judge()
|
||||||
.setSubmitId(submitId)
|
.setSubmitId(submitId)
|
||||||
.setStatus(Constants.Judge.STATUS_JUDGING.getStatus())
|
.setStatus(Constants.Judge.STATUS_PENDING.getStatus())
|
||||||
.setJudger(name)
|
.setJudger(name)
|
||||||
);
|
);
|
||||||
|
|
||||||
// 调用获取远程判题结果
|
// 调用获取远程判题结果
|
||||||
remoteJudgeGetResult.sendTask(remoteJudge, username, submitId, uid, cid, pid,
|
remoteJudgeGetResult.sendTask(remoteJudge, username, submitId, uid, cid, pid,
|
||||||
(Long) submitResult.get("runId"), (String) submitResult.get("token"),
|
(Long) submitResult.get("runId"), (String) submitResult.get("cookies"));
|
||||||
(HashMap<String, String>) submitResult.get("cookies"));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ import com.gargoylesoftware.htmlunit.SilentCssErrorHandler;
|
||||||
import com.gargoylesoftware.htmlunit.WebClient;
|
import com.gargoylesoftware.htmlunit.WebClient;
|
||||||
import com.gargoylesoftware.htmlunit.html.*;
|
import com.gargoylesoftware.htmlunit.html.*;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jsoup.Connection;
|
|
||||||
import top.hcode.hoj.remoteJudge.task.RemoteJudgeStrategy;
|
import top.hcode.hoj.remoteJudge.task.RemoteJudgeStrategy;
|
||||||
import top.hcode.hoj.util.Constants;
|
import top.hcode.hoj.util.Constants;
|
||||||
|
|
||||||
|
@ -73,16 +72,15 @@ public class CodeForcesJudge implements RemoteJudgeStrategy {
|
||||||
|
|
||||||
// 获取提交的题目id
|
// 获取提交的题目id
|
||||||
|
|
||||||
Long maxRunId = getMaxRunId(null, username, problemId);
|
Long maxRunId = getMaxRunId(username, problemId);
|
||||||
|
|
||||||
return MapUtil.builder(new HashMap<String, Object>())
|
return MapUtil.builder(new HashMap<String, Object>())
|
||||||
.put("runId", maxRunId)
|
.put("runId", maxRunId)
|
||||||
.put("token", "")
|
.put("cookies", null)
|
||||||
.put("cookies", new HashMap<String, String>())
|
|
||||||
.map();
|
.map();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Long getMaxRunId(Connection connection, String username, String problemId) throws InterruptedException {
|
private Long getMaxRunId(String username, String problemId) throws InterruptedException {
|
||||||
int retryNum = 0;
|
int retryNum = 0;
|
||||||
String url = String.format(SUBMISSION_RESULT_URL, username);
|
String url = String.format(SUBMISSION_RESULT_URL, username);
|
||||||
HttpRequest httpRequest = HttpUtil.createGet(HOST + url);
|
HttpRequest httpRequest = HttpUtil.createGet(HOST + url);
|
||||||
|
@ -118,7 +116,7 @@ public class CodeForcesJudge implements RemoteJudgeStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> result(Long submitId, String username, String token, HashMap<String, String> cookies) throws Exception {
|
public Map<String, Object> result(Long submitId, String username, String cookies) {
|
||||||
|
|
||||||
String url = HOST + String.format(SUBMISSION_RESULT_URL, username);
|
String url = HOST + String.format(SUBMISSION_RESULT_URL, username);
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,13 @@ package top.hcode.hoj.remoteJudge.task.Impl;
|
||||||
|
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.util.ReUtil;
|
import cn.hutool.core.util.ReUtil;
|
||||||
import cn.hutool.http.HtmlUtil;
|
import cn.hutool.http.*;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jsoup.Connection;
|
|
||||||
import org.jsoup.helper.Validate;
|
import org.jsoup.helper.Validate;
|
||||||
import org.jsoup.nodes.Document;
|
|
||||||
import top.hcode.hoj.pojo.entity.Problem;
|
|
||||||
import top.hcode.hoj.remoteJudge.task.RemoteJudgeStrategy;
|
import top.hcode.hoj.remoteJudge.task.RemoteJudgeStrategy;
|
||||||
import top.hcode.hoj.util.Constants;
|
import top.hcode.hoj.util.Constants;
|
||||||
import top.hcode.hoj.util.JsoupUtils;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -31,6 +29,7 @@ public class HduJudge implements RemoteJudgeStrategy {
|
||||||
.put("Host", "acm.hdu.edu.cn")
|
.put("Host", "acm.hdu.edu.cn")
|
||||||
.put("origin", "http://acm.hdu.edu.cn")
|
.put("origin", "http://acm.hdu.edu.cn")
|
||||||
.put("referer", "http://acm.hdu.edu.cn")
|
.put("referer", "http://acm.hdu.edu.cn")
|
||||||
|
.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36")
|
||||||
.map();
|
.map();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,39 +44,46 @@ public class HduJudge implements RemoteJudgeStrategy {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Map<String, Object> loginUtils = getLoginUtils(username, password);
|
Map<String, Object> loginUtils = getLoginUtils(username, password);
|
||||||
Map<String, String> loginCookie = (Map<String, String>) loginUtils.get("cookie");
|
String cookies = (String) loginUtils.get("cookie");
|
||||||
Connection connection = JsoupUtils.getConnectionFromUrl(HOST + SUBMIT_URL, headers, loginCookie);
|
|
||||||
Connection.Response response = JsoupUtils.postResponse(connection, MapUtil
|
HttpRequest request = HttpUtil.createPost(HOST + SUBMIT_URL)
|
||||||
.builder(new HashMap<String, String>())
|
.addHeaders(headers)
|
||||||
|
.cookie(cookies);
|
||||||
|
|
||||||
|
HttpResponse response = request.form(MapUtil
|
||||||
|
.builder(new HashMap<String, Object>())
|
||||||
.put("check", "0")
|
.put("check", "0")
|
||||||
.put("language", getLanguage(language))
|
.put("language", getLanguage(language))
|
||||||
.put("problemid", problemId)
|
.put("problemid", problemId)
|
||||||
.put("usercode", userCode)
|
.put("usercode", userCode)
|
||||||
.map());
|
.map())
|
||||||
if (response.statusCode() != 200) {
|
.execute();
|
||||||
|
if (response.getStatus() != 200) {
|
||||||
log.error("进行题目提交时发生错误:提交题目失败," + HduJudge.class.getName() + ",题号:" + problemId);
|
log.error("进行题目提交时发生错误:提交题目失败," + HduJudge.class.getName() + ",题号:" + problemId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// 下面的请求都是GET
|
||||||
|
request.setMethod(Method.GET);
|
||||||
// 获取提交的题目id
|
// 获取提交的题目id
|
||||||
Long maxRunId = getMaxRunId(connection, username, problemId);
|
Long maxRunId = getMaxRunId(request, username, problemId);
|
||||||
|
|
||||||
if (maxRunId == -1L) { // 等待2s再次查询,如果还是失败,则表明提交失败了
|
if (maxRunId == -1L) { // 等待2s再次查询,如果还是失败,则表明提交失败了
|
||||||
TimeUnit.SECONDS.sleep(2);
|
TimeUnit.SECONDS.sleep(2);
|
||||||
maxRunId = getMaxRunId(connection, username, problemId);
|
maxRunId = getMaxRunId(request, username, problemId);
|
||||||
}
|
}
|
||||||
return MapUtil.builder(new HashMap<String, Object>())
|
return MapUtil.builder(new HashMap<String, Object>())
|
||||||
.put("token", null)
|
.put("cookies", cookies)
|
||||||
.put("cookies", loginCookie)
|
|
||||||
.put("runId", maxRunId)
|
.put("runId", maxRunId)
|
||||||
.map();
|
.map();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> result(Long submitId, String username, String token, HashMap<String, String> cookies) throws Exception {
|
public Map<String, Object> result(Long submitId, String username, String cookies) throws Exception {
|
||||||
String url = HOST + String.format(QUERY_URL, submitId);
|
String url = HOST + String.format(QUERY_URL, submitId);
|
||||||
Connection connection = JsoupUtils.getConnectionFromUrl(url, headers, null);
|
HttpRequest request = HttpUtil.createGet(url)
|
||||||
Connection.Response response = JsoupUtils.getResponse(connection, null);
|
.cookie(cookies)
|
||||||
|
.addHeaders(headers);
|
||||||
|
HttpResponse response = request.execute();
|
||||||
// 1提交时间 2结果 3执行时间 4执行空间 5代码长度
|
// 1提交时间 2结果 3执行时间 4执行空间 5代码长度
|
||||||
// 一般情况下 代码长度和提交时间不需要,想要也行,自行添加
|
// 一般情况下 代码长度和提交时间不需要,想要也行,自行添加
|
||||||
Pattern pattern = Pattern.compile(">" + submitId + "</td><td>([\\s\\S]*?)</td><td>([\\s\\S]*?)</td><td>[\\s\\S]*?</td><td>(\\d*?)MS</td><td>(\\d*?)K</td><td>(\\d*?)B</td>");
|
Pattern pattern = Pattern.compile(">" + submitId + "</td><td>([\\s\\S]*?)</td><td>([\\s\\S]*?)</td><td>[\\s\\S]*?</td><td>(\\d*?)MS</td><td>(\\d*?)K</td><td>(\\d*?)B</td>");
|
||||||
|
@ -100,9 +106,9 @@ public class HduJudge implements RemoteJudgeStrategy {
|
||||||
result.put("memory", Integer.parseInt(executionMemory));
|
result.put("memory", Integer.parseInt(executionMemory));
|
||||||
// 如果CE了,则还需要获得错误信息
|
// 如果CE了,则还需要获得错误信息
|
||||||
if (statusType == Constants.Judge.STATUS_COMPILE_ERROR) {
|
if (statusType == Constants.Judge.STATUS_COMPILE_ERROR) {
|
||||||
connection.url(HOST + String.format(ERROR_URL, submitId));
|
request.setUrl(HOST + String.format(ERROR_URL, submitId));
|
||||||
response = JsoupUtils.getResponse(connection, null);
|
String CEHtml = request.execute().body();
|
||||||
String compilationErrorInfo = ReUtil.get("<pre>([\\s\\S]*?)</pre>", response.body(), 1);
|
String compilationErrorInfo = ReUtil.get("<pre>([\\s\\S]*?)</pre>", CEHtml, 1);
|
||||||
result.put("CEInfo", HtmlUtil.unescape(compilationErrorInfo));
|
result.put("CEInfo", HtmlUtil.unescape(compilationErrorInfo));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -110,14 +116,16 @@ public class HduJudge implements RemoteJudgeStrategy {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> getLoginUtils(String username, String password) throws Exception {
|
public Map<String, Object> getLoginUtils(String username, String password){
|
||||||
Connection connection = JsoupUtils.getConnectionFromUrl(HOST + LOGIN_URL, headers, null);
|
|
||||||
Connection.Response response = JsoupUtils.postResponse(connection, MapUtil
|
HttpRequest request = HttpUtil.createPost(HOST + LOGIN_URL).addHeaders(headers);
|
||||||
.builder(new HashMap<String, String>())
|
HttpResponse response = request.form(MapUtil
|
||||||
|
.builder(new HashMap<String, Object>())
|
||||||
.put("username", username)
|
.put("username", username)
|
||||||
.put("login", "Sign In")
|
.put("login", "Sign In")
|
||||||
.put("userpass", password).map());
|
.put("userpass", password).map())
|
||||||
return MapUtil.builder(new HashMap<String, Object>()).put("cookie", response.cookies()).map();
|
.execute();
|
||||||
|
return MapUtil.builder(new HashMap<String, Object>()).put("cookie", response.getCookieStr()).map();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -144,10 +152,9 @@ public class HduJudge implements RemoteJudgeStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Long getMaxRunId(Connection connection, String userName, String problemId) throws Exception {
|
public Long getMaxRunId(HttpRequest request, String userName, String problemId){
|
||||||
String url = String.format(STATUS_URL, userName, problemId);
|
String url = String.format(STATUS_URL, userName, problemId);
|
||||||
connection.url(HOST + url);
|
HttpResponse response = request.setUrl(url).execute();
|
||||||
Connection.Response response = JsoupUtils.getResponse(connection, null);
|
|
||||||
Matcher matcher = Pattern.compile("<td height=22px>(\\d+)").matcher(response.body());
|
Matcher matcher = Pattern.compile("<td height=22px>(\\d+)").matcher(response.body());
|
||||||
return matcher.find() ? Long.parseLong(matcher.group(1)) : -1L;
|
return matcher.find() ? Long.parseLong(matcher.group(1)) : -1L;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,178 @@
|
||||||
|
package top.hcode.hoj.remoteJudge.task.Impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.codec.Base64;
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.hutool.core.util.ReUtil;
|
||||||
|
import cn.hutool.http.*;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import top.hcode.hoj.remoteJudge.task.RemoteJudgeStrategy;
|
||||||
|
import top.hcode.hoj.util.Constants;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: Himit_ZH
|
||||||
|
* @Date: 2021/6/24 21:19
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
@Slf4j(topic = "hoj")
|
||||||
|
public class POJJudge implements RemoteJudgeStrategy {
|
||||||
|
public static final String HOST = "http://poj.org";
|
||||||
|
public static final String LOGIN_URL = "/login";
|
||||||
|
public static final String SUBMIT_URL = "/submit";
|
||||||
|
public static final String STATUS_URL = "/status?user_id=%s&problem_id=%s";
|
||||||
|
public static final String QUERY_URL = "/showsource?solution_id=%s";
|
||||||
|
public static final String ERROR_URL = "/showcompileinfo?solution_id=%s";
|
||||||
|
public static Map<String, String> headers = MapUtil
|
||||||
|
.builder(new HashMap<String, String>())
|
||||||
|
.put("Host", "poj.org")
|
||||||
|
.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36")
|
||||||
|
.map();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param problemId 提交的题目id
|
||||||
|
* @param language
|
||||||
|
* @param userCode 用户代码
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> submit(String username, String password, String problemId, String language, String userCode) throws Exception {
|
||||||
|
if (problemId == null || userCode == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Map<String, Object> loginUtils = getLoginUtils(username, password);
|
||||||
|
String cookies = (String) loginUtils.get("cookie");
|
||||||
|
|
||||||
|
HttpRequest request = HttpUtil.createPost(HOST + SUBMIT_URL)
|
||||||
|
.addHeaders(headers)
|
||||||
|
.cookie(cookies);
|
||||||
|
|
||||||
|
HttpResponse response = request.form(MapUtil.builder(new HashMap<String, Object>())
|
||||||
|
.put("language", getLanguage(language))
|
||||||
|
.put("submit", "Submit")
|
||||||
|
.put("problem_id", problemId)
|
||||||
|
.put("source", Base64.encode(userCode))
|
||||||
|
.put("encoded", 1).map())
|
||||||
|
.execute();
|
||||||
|
if (response.getStatus() != 302) {
|
||||||
|
log.error("进行题目提交时发生错误:提交题目失败," + POJJudge.class.getName() + ",题号:" + problemId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 下面的请求都是GET
|
||||||
|
request.setMethod(Method.GET);
|
||||||
|
// 获取提交的题目id
|
||||||
|
Long maxRunId = getMaxRunId(request, username, problemId);
|
||||||
|
|
||||||
|
if (maxRunId == -1L) { // 等待2s再次查询,如果还是失败,则表明提交失败了
|
||||||
|
TimeUnit.SECONDS.sleep(2);
|
||||||
|
maxRunId = getMaxRunId(request, username, problemId);
|
||||||
|
}
|
||||||
|
return MapUtil.builder(new HashMap<String, Object>())
|
||||||
|
.put("cookies", cookies)
|
||||||
|
.put("runId", maxRunId)
|
||||||
|
.map();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> result(Long submitId, String username, String cookies) {
|
||||||
|
String url = HOST + String.format(QUERY_URL, submitId);
|
||||||
|
HttpRequest request = HttpUtil.createGet(url)
|
||||||
|
.cookie(cookies)
|
||||||
|
.addHeaders(headers);
|
||||||
|
HttpResponse response = request.execute();
|
||||||
|
|
||||||
|
String statusStr = ReUtil.get("<b>Result:</b>(.+?)</td>", response.body(), 1)
|
||||||
|
.replaceAll("<.*?>", "")
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
Constants.Judge statusType = statusTypeMap.getOrDefault(statusStr, null);
|
||||||
|
|
||||||
|
if (statusType == null) {
|
||||||
|
return MapUtil.builder(new HashMap<String, Object>())
|
||||||
|
.put("status", Constants.Judge.STATUS_PENDING).build();
|
||||||
|
}
|
||||||
|
// 返回的结果map
|
||||||
|
Map<String, Object> result = MapUtil.builder(new HashMap<String, Object>())
|
||||||
|
.put("status", statusType.getStatus()).build();
|
||||||
|
// 如果CE了,需要获得错误信息
|
||||||
|
if (statusType == Constants.Judge.STATUS_COMPILE_ERROR) {
|
||||||
|
request.setUrl(HOST + String.format(ERROR_URL, submitId));
|
||||||
|
String CEHtml = request.execute().body();
|
||||||
|
String compilationErrorInfo = ReUtil.get("<pre>([\\s\\S]*?)</pre>", CEHtml, 1);
|
||||||
|
result.put("CEInfo", HtmlUtil.unescape(compilationErrorInfo));
|
||||||
|
} else {
|
||||||
|
// 如果不是CE,获取其他信息
|
||||||
|
String executionTime = ReUtil.get("<b>Memory:</b> ([-\\d]+)", response.body(), 1);
|
||||||
|
result.put("time", Integer.parseInt(executionTime));
|
||||||
|
String executionMemory = ReUtil.get("<b>Time:</b> ([-\\d]+)", response.body(), 1);
|
||||||
|
result.put("memory", Integer.parseInt(executionMemory));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getLoginUtils(String username, String password) {
|
||||||
|
|
||||||
|
HttpRequest request = HttpUtil.createPost(HOST + LOGIN_URL);
|
||||||
|
HttpResponse response = request.form(MapUtil.builder(new HashMap<String, Object>())
|
||||||
|
.put("user_id1", username)
|
||||||
|
.put("B1", "login")
|
||||||
|
.put("url", ".")
|
||||||
|
.put("password1", password).map()).execute();
|
||||||
|
|
||||||
|
return MapUtil.builder(new HashMap<String, Object>()).put("cookie", response.getCookieStr()).map();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLanguage(String language) {
|
||||||
|
switch (language) {
|
||||||
|
case "G++":
|
||||||
|
return "0";
|
||||||
|
case "GCC":
|
||||||
|
return "1";
|
||||||
|
case "Java":
|
||||||
|
return "2";
|
||||||
|
case "Pascal":
|
||||||
|
return "3";
|
||||||
|
case "C++":
|
||||||
|
return "4";
|
||||||
|
case "C":
|
||||||
|
return "5";
|
||||||
|
case "Fortran":
|
||||||
|
return "6";
|
||||||
|
default:
|
||||||
|
// TODO 抛出没有这个语言的异常
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Long getMaxRunId(HttpRequest request, String userName, String problemId) {
|
||||||
|
String url = String.format(STATUS_URL, userName, problemId);
|
||||||
|
request.setUrl(HOST + url);
|
||||||
|
String html = request.execute().body();
|
||||||
|
Matcher matcher = Pattern.compile("<tr align=center><td>(\\d+)").matcher(html);
|
||||||
|
return matcher.find() ? Long.parseLong(matcher.group(1)) : -1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO 添加结果对应的状态
|
||||||
|
private static final Map<String, Constants.Judge> statusTypeMap = new HashMap<String, Constants.Judge>() {
|
||||||
|
{
|
||||||
|
put("Compiling", Constants.Judge.STATUS_COMPILING);
|
||||||
|
put("Accepted", Constants.Judge.STATUS_ACCEPTED);
|
||||||
|
put("Presentation Error", Constants.Judge.STATUS_PRESENTATION_ERROR);
|
||||||
|
put("Time Limit Exceeded", Constants.Judge.STATUS_TIME_LIMIT_EXCEEDED);
|
||||||
|
put("Memory Limit Exceeded", Constants.Judge.STATUS_MEMORY_LIMIT_EXCEEDED);
|
||||||
|
put("Wrong Answer", Constants.Judge.STATUS_WRONG_ANSWER);
|
||||||
|
put("Runtime Error", Constants.Judge.STATUS_RUNTIME_ERROR);
|
||||||
|
put("Output Limit Exceeded", Constants.Judge.STATUS_RUNTIME_ERROR);
|
||||||
|
put("Compile Error", Constants.Judge.STATUS_COMPILE_ERROR);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package top.hcode.hoj.remoteJudge.task;
|
||||||
|
|
||||||
import top.hcode.hoj.remoteJudge.task.Impl.CodeForcesJudge;
|
import top.hcode.hoj.remoteJudge.task.Impl.CodeForcesJudge;
|
||||||
import top.hcode.hoj.remoteJudge.task.Impl.HduJudge;
|
import top.hcode.hoj.remoteJudge.task.Impl.HduJudge;
|
||||||
|
import top.hcode.hoj.remoteJudge.task.Impl.POJJudge;
|
||||||
import top.hcode.hoj.util.Constants;
|
import top.hcode.hoj.util.Constants;
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,6 +15,8 @@ public class RemoteJudgeFactory {
|
||||||
return new HduJudge();
|
return new HduJudge();
|
||||||
case CF_JUDGE:
|
case CF_JUDGE:
|
||||||
return new CodeForcesJudge();
|
return new CodeForcesJudge();
|
||||||
|
case POJ_JUDGE:
|
||||||
|
return new POJJudge();
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ public interface RemoteJudgeStrategy {
|
||||||
* @param username 题库的提交者的账号
|
* @param username 题库的提交者的账号
|
||||||
* @return 返回结果
|
* @return 返回结果
|
||||||
*/
|
*/
|
||||||
Map<String, Object> result(Long submitId, String username, String token, HashMap<String,String> cookies) throws Exception;
|
Map<String, Object> result(Long submitId, String username, String cookies) throws Exception;
|
||||||
|
|
||||||
Map<String, Object> getLoginUtils(String username, String password) throws Exception;
|
Map<String, Object> getLoginUtils(String username, String password) throws Exception;
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,8 @@ public class Constants {
|
||||||
|
|
||||||
CF_JUDGE("CF"),
|
CF_JUDGE("CF"),
|
||||||
|
|
||||||
|
POJ_JUDGE("POJ"),
|
||||||
|
|
||||||
HDU_REMOTE_JUDGE_ACCOUNT("Hdu Remote Judge Account"),
|
HDU_REMOTE_JUDGE_ACCOUNT("Hdu Remote Judge Account"),
|
||||||
|
|
||||||
CF_REMOTE_JUDGE_ACCOUNT("Codeforces Remote Judge Account");
|
CF_REMOTE_JUDGE_ACCOUNT("Codeforces Remote Judge Account");
|
||||||
|
|
|
@ -88,4 +88,6 @@ public class JudgeServerApplicationTests {
|
||||||
"}");
|
"}");
|
||||||
System.out.println(result);
|
System.out.println(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,10 @@ public class Discussion {
|
||||||
private Integer viewNum;
|
private Integer viewNum;
|
||||||
|
|
||||||
@ApiModelProperty(value = "点赞数量")
|
@ApiModelProperty(value = "点赞数量")
|
||||||
private String likeNum;
|
private Integer likeNum;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "评论数量,包括其评论及其回复数")
|
||||||
|
private Integer commentNum;
|
||||||
|
|
||||||
@ApiModelProperty(value = "优先级,是否置顶")
|
@ApiModelProperty(value = "优先级,是否置顶")
|
||||||
private Boolean topPriority;
|
private Boolean topPriority;
|
||||||
|
|
|
@ -45,7 +45,7 @@ public class Problem implements Serializable {
|
||||||
@ApiModelProperty(value = "单位ms")
|
@ApiModelProperty(value = "单位ms")
|
||||||
private Integer timeLimit;
|
private Integer timeLimit;
|
||||||
|
|
||||||
@ApiModelProperty(value = "单位kb")
|
@ApiModelProperty(value = "单位mb")
|
||||||
private Integer memoryLimit;
|
private Integer memoryLimit;
|
||||||
|
|
||||||
@ApiModelProperty(value = "单位mb")
|
@ApiModelProperty(value = "单位mb")
|
||||||
|
@ -104,6 +104,9 @@ public class Problem implements Serializable {
|
||||||
@ApiModelProperty(value = "题目测试数据的版本号")
|
@ApiModelProperty(value = "题目测试数据的版本号")
|
||||||
private String caseVersion;
|
private String caseVersion;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "修改题目的管理员用户名")
|
||||||
|
private String modifiedUser;
|
||||||
|
|
||||||
@TableField(fill = FieldFill.INSERT)
|
@TableField(fill = FieldFill.INSERT)
|
||||||
private Date gmtCreate;
|
private Date gmtCreate;
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,8 @@ export const PROBLEM_LEVEL_RESERVE={
|
||||||
|
|
||||||
export const REMOTE_OJ = [
|
export const REMOTE_OJ = [
|
||||||
{name:'HDU',key:"HDU"},
|
{name:'HDU',key:"HDU"},
|
||||||
{name:"Codeforces",key:"CF"}
|
{name:"Codeforces",key:"CF"},
|
||||||
|
{name:"POJ",key:"POJ"},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const CONTEST_STATUS = {
|
export const CONTEST_STATUS = {
|
||||||
|
|
|
@ -622,7 +622,10 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.replyObj.content = this.replyInputComment;
|
this.replyObj.content = this.replyInputComment;
|
||||||
let replyData = Object.assign({}, this.replyObj);
|
let replyData = {
|
||||||
|
reply: this.replyObj,
|
||||||
|
did: this.did,
|
||||||
|
};
|
||||||
api.addReply(replyData).then((res) => {
|
api.addReply(replyData).then((res) => {
|
||||||
for (let i = 0; i < this.comments.length; i++) {
|
for (let i = 0; i < this.comments.length; i++) {
|
||||||
if (this.comments[i].id == this.replyObj.commentId) {
|
if (this.comments[i].id == this.replyObj.commentId) {
|
||||||
|
@ -715,6 +718,7 @@ export default {
|
||||||
.then(() => {
|
.then(() => {
|
||||||
let replyDeleteData = {
|
let replyDeleteData = {
|
||||||
id: reply.id,
|
id: reply.id,
|
||||||
|
did: this.did,
|
||||||
fromUid: reply.fromUid,
|
fromUid: reply.fromUid,
|
||||||
};
|
};
|
||||||
api.deleteReply(replyDeleteData).then((res) => {
|
api.deleteReply(replyDeleteData).then((res) => {
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div style="margin: 0px 0px 15px 0px;font-size: 14px;">
|
<div style="margin: 0px 0px 15px 0px;font-size: 14px;">
|
||||||
<el-row class="header">
|
<el-row class="header">
|
||||||
<el-col :xs="24" :sm="14" :md="14" :lg="14">
|
<el-col :xs="24" :sm="15" :md="15" :lg="15">
|
||||||
<div class="select-row">
|
<div class="select-row">
|
||||||
<span>{{ $t('m.Lang') }}:</span>
|
<span>{{ $t('m.Lang') }}:</span>
|
||||||
<span>
|
<span>
|
||||||
<el-select
|
<el-select
|
||||||
:value="this.language"
|
:value="this.language"
|
||||||
@change="onLangChange"
|
@change="onLangChange"
|
||||||
class="adjust"
|
class="left-adjust"
|
||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
<el-option v-for="item in languages" :key="item" :value="item"
|
<el-option v-for="item in languages" :key="item" :value="item"
|
||||||
|
@ -44,13 +44,13 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :sm="10" :md="10" :lg="10">
|
<el-col :xs="24" :sm="9" :md="9" :lg="9">
|
||||||
<div class="select-row fl-right">
|
<div class="select-row fl-right">
|
||||||
<span>{{ $t('m.Theme') }}:</span>
|
<span>{{ $t('m.Theme') }}:</span>
|
||||||
<el-select
|
<el-select
|
||||||
:value="this.theme"
|
:value="this.theme"
|
||||||
@change="onThemeChange"
|
@change="onThemeChange"
|
||||||
class="adjust"
|
class="right-adjust"
|
||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
|
@ -104,6 +104,7 @@ import 'codemirror/mode/php/php.js'; //php
|
||||||
import 'codemirror/mode/ruby/ruby.js'; //ruby
|
import 'codemirror/mode/ruby/ruby.js'; //ruby
|
||||||
import 'codemirror/mode/rust/rust.js'; //rust
|
import 'codemirror/mode/rust/rust.js'; //rust
|
||||||
import 'codemirror/mode/javascript/javascript.js'; //javascript
|
import 'codemirror/mode/javascript/javascript.js'; //javascript
|
||||||
|
import 'codemirror/mode/fortran/fortran.js'; //fortran
|
||||||
|
|
||||||
// active-line.js
|
// active-line.js
|
||||||
import 'codemirror/addon/selection/active-line.js';
|
import 'codemirror/addon/selection/active-line.js';
|
||||||
|
@ -260,10 +261,15 @@ export default {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
.header .adjust {
|
.header .left-adjust {
|
||||||
width: 170px;
|
width: 170px;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
.header .right-adjust {
|
||||||
|
width: 140px;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.select-row {
|
.select-row {
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,7 @@ export const m = {
|
||||||
Add_Rmote_OJ_Problem:'Add Remote OJ Problem',
|
Add_Rmote_OJ_Problem:'Add Remote OJ Problem',
|
||||||
Add_From_Public_Problem:'Add From Public Problem',
|
Add_From_Public_Problem:'Add From Public Problem',
|
||||||
Auth:'Auth',
|
Auth:'Auth',
|
||||||
|
Modified_User:'Modified User',
|
||||||
Public_Problem:'Public Problem',
|
Public_Problem:'Public Problem',
|
||||||
Private_Problem:'Private Problem',
|
Private_Problem:'Private Problem',
|
||||||
Contest_Problem:'Contest Problem',
|
Contest_Problem:'Contest Problem',
|
||||||
|
|
|
@ -126,6 +126,7 @@ export const m = {
|
||||||
Add_Rmote_OJ_Problem:'添加远程OJ题目',
|
Add_Rmote_OJ_Problem:'添加远程OJ题目',
|
||||||
Add_From_Public_Problem:'从公共题库添加题目',
|
Add_From_Public_Problem:'从公共题库添加题目',
|
||||||
Auth:'权限',
|
Auth:'权限',
|
||||||
|
Modified_User:'最近修改者',
|
||||||
Public_Problem:'公开题目',
|
Public_Problem:'公开题目',
|
||||||
Private_Problem:'隐藏题目',
|
Private_Problem:'隐藏题目',
|
||||||
Contest_Problem:'比赛题目',
|
Contest_Problem:'比赛题目',
|
||||||
|
|
|
@ -164,6 +164,10 @@ export const m = {
|
||||||
Good_luck_to_you:'Good luck to you!',
|
Good_luck_to_you:'Good luck to you!',
|
||||||
|
|
||||||
// /views/oj/problem/Problem.vue
|
// /views/oj/problem/Problem.vue
|
||||||
|
Shrink_Sidebar:'Shrink Sidebar',
|
||||||
|
View_Problem_Content:'View Problem Content',
|
||||||
|
Only_View_Problem:'Only View Problem',
|
||||||
|
Put_away_the_full_screen_and_write_the_code:'Put away the full screen and write the code',
|
||||||
Contest_Problem:'Contest Problem',
|
Contest_Problem:'Contest Problem',
|
||||||
Show_Tags:'Show tags',
|
Show_Tags:'Show tags',
|
||||||
No_tag:'No tag',
|
No_tag:'No tag',
|
||||||
|
|
|
@ -165,6 +165,10 @@ export const m = {
|
||||||
Good_luck_to_you:'祝你好运!',
|
Good_luck_to_you:'祝你好运!',
|
||||||
|
|
||||||
// /views/oj/problem/Problem.vue
|
// /views/oj/problem/Problem.vue
|
||||||
|
Shrink_Sidebar:'收缩侧边栏',
|
||||||
|
View_Problem_Content:'查看题目内容',
|
||||||
|
Only_View_Problem:'只看题目内容',
|
||||||
|
Put_away_the_full_screen_and_write_the_code:'收起全屏,编写代码',
|
||||||
Contest_Problem:'比赛题目',
|
Contest_Problem:'比赛题目',
|
||||||
Show_Tags:'显示标签',
|
Show_Tags:'显示标签',
|
||||||
No_tag:'暂无标签',
|
No_tag:'暂无标签',
|
||||||
|
@ -243,7 +247,7 @@ export const m = {
|
||||||
OI_Ranklist: 'OI 排行榜',
|
OI_Ranklist: 'OI 排行榜',
|
||||||
|
|
||||||
// /views/oj/discussion/discussionList.vue
|
// /views/oj/discussion/discussionList.vue
|
||||||
Created_Time:'创建时间',
|
Created_Time:'发布时间',
|
||||||
Likes:'点赞',
|
Likes:'点赞',
|
||||||
Views:'浏览',
|
Views:'浏览',
|
||||||
Edit:'编辑',
|
Edit:'编辑',
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
</vxe-table-column>
|
</vxe-table-column>
|
||||||
<vxe-table-column
|
<vxe-table-column
|
||||||
field="author"
|
field="author"
|
||||||
min-width="150"
|
min-width="130"
|
||||||
:title="$t('m.Author')"
|
:title="$t('m.Author')"
|
||||||
>
|
>
|
||||||
</vxe-table-column>
|
</vxe-table-column>
|
||||||
|
@ -73,6 +73,12 @@
|
||||||
{{ row.gmtCreate | localtime }}
|
{{ row.gmtCreate | localtime }}
|
||||||
</template>
|
</template>
|
||||||
</vxe-table-column>
|
</vxe-table-column>
|
||||||
|
<vxe-table-column
|
||||||
|
field="modifiedUser"
|
||||||
|
min-width="130"
|
||||||
|
:title="$t('m.Modified_User')"
|
||||||
|
>
|
||||||
|
</vxe-table-column>
|
||||||
<vxe-table-column min-width="130" field="auth" :title="$t('m.Auth')">
|
<vxe-table-column min-width="130" field="auth" :title="$t('m.Auth')">
|
||||||
<template v-slot="{ row }">
|
<template v-slot="{ row }">
|
||||||
<el-select
|
<el-select
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
{{ discussion.title }}
|
{{ discussion.title }}
|
||||||
</h1>
|
</h1>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
@click="toDiscussionDetail(discussion.id)"
|
@click="toDiscussionDetail(discussion.id)"
|
||||||
class="article-hlink2"
|
class="article-hlink2"
|
||||||
|
@ -101,30 +102,30 @@
|
||||||
>ADM</span
|
>ADM</span
|
||||||
>
|
>
|
||||||
</span>
|
</span>
|
||||||
<span class="pr pl hidden-xs-only"
|
|
||||||
><label class="fw"><i class="fa fa-clock-o"></i></label
|
<span class="pr pl"
|
||||||
|
><label class="fw"><i class="el-icon-chat-round"></i></label
|
||||||
><span>
|
><span>
|
||||||
{{ $t('m.Created_Time') }}:<el-tooltip
|
<span class="hidden-xs-only"> {{ $t('m.Comment') }}:</span>
|
||||||
:content="discussion.gmtCreate | localtime"
|
{{ discussion.commentNum }}</span
|
||||||
placement="top"
|
|
||||||
>
|
|
||||||
<span>{{ discussion.gmtCreate | fromNow }}</span>
|
|
||||||
</el-tooltip></span
|
|
||||||
></span
|
></span
|
||||||
>
|
>
|
||||||
|
|
||||||
<span class="pr"
|
<span class="pr"
|
||||||
><label class="fw"><i class="fa fa-thumbs-o-up"></i></label
|
><label class="fw"><i class="fa fa-thumbs-o-up"></i></label
|
||||||
><span>
|
><span>
|
||||||
{{ $t('m.Likes') }}:{{ discussion.likeNum }}</span
|
<span class="hidden-xs-only"> {{ $t('m.Likes') }}:</span>
|
||||||
|
{{ discussion.likeNum }}</span
|
||||||
></span
|
></span
|
||||||
>
|
>
|
||||||
<span class="pr"
|
<span class="pr"
|
||||||
><label class="fw"><i class="fa fa-eye"></i></label
|
><label class="fw"><i class="fa fa-eye"></i></label
|
||||||
><span>
|
><span>
|
||||||
{{ $t('m.Views') }}:{{ discussion.viewNum }}</span
|
<span class="hidden-xs-only"> {{ $t('m.Views') }}:</span>
|
||||||
|
{{ discussion.viewNum }}</span
|
||||||
></span
|
></span
|
||||||
>
|
>
|
||||||
<span
|
<span class="pr"
|
||||||
><label class="fw"><i class="el-icon-folder-opened"></i></label>
|
><label class="fw"><i class="el-icon-folder-opened"></i></label>
|
||||||
<a
|
<a
|
||||||
@click="
|
@click="
|
||||||
|
@ -139,6 +140,18 @@
|
||||||
>
|
>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
<span class="pr pl hidden-xs-only">
|
||||||
|
<label class="fw"><i class="fa fa-clock-o"></i></label
|
||||||
|
><span>
|
||||||
|
{{ $t('m.Created_Time') }}:<el-tooltip
|
||||||
|
:content="discussion.gmtCreate | localtime"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<span>{{ discussion.gmtCreate | fromNow }}</span>
|
||||||
|
</el-tooltip></span
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
|
||||||
<el-dropdown
|
<el-dropdown
|
||||||
style="float:right;"
|
style="float:right;"
|
||||||
class="hidden-xs-only"
|
class="hidden-xs-only"
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
<div>
|
<div>
|
||||||
<div id="problem-main">
|
<div id="problem-main">
|
||||||
<!--problem main-->
|
<!--problem main-->
|
||||||
<el-row>
|
<el-row class="problem-box">
|
||||||
<el-col :sm="24" :md="24" :lg="12">
|
<el-col :sm="24" :md="24" :lg="12" class="problem-left">
|
||||||
<el-card :padding="10" shadow class="problem-detail">
|
<el-card :padding="10" shadow class="problem-detail">
|
||||||
<div slot="header" class="panel-title">
|
<div slot="header" class="panel-title">
|
||||||
<span>{{ problemData.problem.title }}</span
|
<span>{{ problemData.problem.title }}</span
|
||||||
|
@ -172,7 +172,42 @@
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :sm="24" :md="24" :lg="12">
|
<div
|
||||||
|
class="problem-resize hidden-md-and-down"
|
||||||
|
:title="$t('m.Shrink_Sidebar')"
|
||||||
|
>
|
||||||
|
<span>⋮</span>
|
||||||
|
<el-tooltip
|
||||||
|
:content="
|
||||||
|
toWatchProblem
|
||||||
|
? $t('m.View_Problem_Content')
|
||||||
|
: $t('m.Only_View_Problem')
|
||||||
|
"
|
||||||
|
placement="right"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
icon="el-icon-caret-right"
|
||||||
|
circle
|
||||||
|
class="right-fold fold"
|
||||||
|
@click.native="onlyWatchProblem"
|
||||||
|
size="mini"
|
||||||
|
></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip
|
||||||
|
:content="$t('m.Put_away_the_full_screen_and_write_the_code')"
|
||||||
|
placement="left"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
icon="el-icon-caret-left"
|
||||||
|
circle
|
||||||
|
class="left-fold fold"
|
||||||
|
@click.native="resetWatch(false)"
|
||||||
|
size="mini"
|
||||||
|
v-show="toResetWatch"
|
||||||
|
></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
<el-col :sm="24" :md="24" :lg="12" class="problem-right">
|
||||||
<el-card
|
<el-card
|
||||||
:padding="10"
|
:padding="10"
|
||||||
id="submit-code"
|
id="submit-code"
|
||||||
|
@ -432,6 +467,8 @@ export default {
|
||||||
JUDGE_STATUS_RESERVE: {},
|
JUDGE_STATUS_RESERVE: {},
|
||||||
PROBLEM_LEVEL: {},
|
PROBLEM_LEVEL: {},
|
||||||
RULE_TYPE: {},
|
RULE_TYPE: {},
|
||||||
|
toResetWatch: false,
|
||||||
|
toWatchProblem: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
// 获取缓存中的该题的做题代码,代码语言,代码风格
|
// 获取缓存中的该题的做题代码,代码语言,代码风格
|
||||||
|
@ -449,6 +486,7 @@ export default {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.JUDGE_STATUS_RESERVE = Object.assign({}, JUDGE_STATUS_RESERVE);
|
this.JUDGE_STATUS_RESERVE = Object.assign({}, JUDGE_STATUS_RESERVE);
|
||||||
this.PROBLEM_LEVEL = Object.assign({}, PROBLEM_LEVEL);
|
this.PROBLEM_LEVEL = Object.assign({}, PROBLEM_LEVEL);
|
||||||
|
@ -456,9 +494,95 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.init();
|
this.init();
|
||||||
|
this.dragControllerDiv();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(['changeDomTitle']),
|
...mapActions(['changeDomTitle']),
|
||||||
|
dragControllerDiv() {
|
||||||
|
var resize = document.getElementsByClassName('problem-resize');
|
||||||
|
var left = document.getElementsByClassName('problem-left');
|
||||||
|
var right = document.getElementsByClassName('problem-right');
|
||||||
|
var box = document.getElementsByClassName('problem-box');
|
||||||
|
const _this = this;
|
||||||
|
for (let i = 0; i < resize.length; i++) {
|
||||||
|
// 鼠标按下事件
|
||||||
|
resize[i].onmousedown = function(e) {
|
||||||
|
//颜色改变提醒
|
||||||
|
resize[i].style.background = '#818181';
|
||||||
|
var startX = e.clientX;
|
||||||
|
// 鼠标拖动事件
|
||||||
|
document.onmousemove = function(e) {
|
||||||
|
resize[i].left = startX;
|
||||||
|
var endX = e.clientX;
|
||||||
|
var moveLen = resize[i].left + (endX - startX); // (endx-startx)=移动的距离。resize[i].left+移动的距离=左边区域最后的宽度
|
||||||
|
var maxT = box[i].clientWidth - resize[i].offsetWidth; // 容器宽度 - 左边区域的宽度 = 右边区域的宽度
|
||||||
|
if (moveLen < 420) moveLen = 0; // 左边区域的最小宽度为420px
|
||||||
|
if (moveLen > maxT - 580) moveLen = maxT - 580; //右边区域最小宽度为580px
|
||||||
|
resize[i].style.left = moveLen; // 设置左侧区域的宽度
|
||||||
|
for (let j = 0; j < left.length; j++) {
|
||||||
|
left[j].style.width = moveLen + 'px';
|
||||||
|
let tmp = box[i].clientWidth - moveLen - 11;
|
||||||
|
right[j].style.width = tmp + 'px';
|
||||||
|
if (tmp > 0) {
|
||||||
|
_this.toResetWatch = false;
|
||||||
|
}
|
||||||
|
if (moveLen == 0) {
|
||||||
|
_this.toWatchProblem = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 鼠标松开事件
|
||||||
|
document.onmouseup = function(evt) {
|
||||||
|
//颜色恢复
|
||||||
|
resize[i].style.background = '#d6d6d6';
|
||||||
|
document.onmousemove = null;
|
||||||
|
document.onmouseup = null;
|
||||||
|
resize[i].releaseCapture && resize[i].releaseCapture(); //当你不在需要继续获得鼠标消息就要应该调用ReleaseCapture()释放掉
|
||||||
|
};
|
||||||
|
resize[i].setCapture && resize[i].setCapture(); //该函数在属于当前线程的指定窗口里设置鼠标捕获
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onlyWatchProblem() {
|
||||||
|
if (this.toWatchProblem) {
|
||||||
|
this.resetWatch(true);
|
||||||
|
this.toWatchProblem = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var resize = document.getElementsByClassName('problem-resize');
|
||||||
|
var left = document.getElementsByClassName('problem-left');
|
||||||
|
var right = document.getElementsByClassName('problem-right');
|
||||||
|
var box = document.getElementsByClassName('problem-box');
|
||||||
|
for (let i = 0; i < resize.length; i++) {
|
||||||
|
resize[i].style.left = box[i].clientWidth - 11;
|
||||||
|
for (let j = 0; j < left.length; j++) {
|
||||||
|
left[j].style.width = box[i].clientWidth - 11 + 'px';
|
||||||
|
right[j].style.width = '0px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.toResetWatch = true;
|
||||||
|
},
|
||||||
|
resetWatch(minLeft = false) {
|
||||||
|
var resize = document.getElementsByClassName('problem-resize');
|
||||||
|
var left = document.getElementsByClassName('problem-left');
|
||||||
|
var right = document.getElementsByClassName('problem-right');
|
||||||
|
var box = document.getElementsByClassName('problem-box');
|
||||||
|
for (let i = 0; i < resize.length; i++) {
|
||||||
|
let leftWidth = 0;
|
||||||
|
if (minLeft) {
|
||||||
|
leftWidth = 431; // 恢复左边最小420px+滑块11px
|
||||||
|
} else {
|
||||||
|
leftWidth = box[i].clientWidth - 580; // 右边最小580px
|
||||||
|
}
|
||||||
|
resize[i].style.left = leftWidth - 11;
|
||||||
|
for (let j = 0; j < left.length; j++) {
|
||||||
|
left[j].style.width = leftWidth - 11 + 'px';
|
||||||
|
right[j].style.width = box[i].clientWidth - leftWidth + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.toResetWatch = false;
|
||||||
|
},
|
||||||
init() {
|
init() {
|
||||||
if (this.$route.params.contestID) {
|
if (this.$route.params.contestID) {
|
||||||
this.contestID = this.$route.params.contestID;
|
this.contestID = this.$route.params.contestID;
|
||||||
|
@ -890,6 +1014,7 @@ export default {
|
||||||
#problem-main {
|
#problem-main {
|
||||||
flex: auto;
|
flex: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.problem-menu {
|
.problem-menu {
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
@ -941,6 +1066,81 @@ a {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 1050px) {
|
||||||
|
.problem-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.problem-left {
|
||||||
|
width: calc(50% - 10px); /*左侧初始化宽度*/
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.problem-resize {
|
||||||
|
cursor: col-resize;
|
||||||
|
float: left;
|
||||||
|
position: relative;
|
||||||
|
top: 330px;
|
||||||
|
background-color: #d6d6d6;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-top: -10px;
|
||||||
|
width: 10px;
|
||||||
|
height: 50px;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
/*z-index: 99999;*/
|
||||||
|
font-size: 32px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.problem-resize:hover .right-fold {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.problem-resize:hover .fold:before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
width: 6px;
|
||||||
|
height: 24px;
|
||||||
|
left: -6px;
|
||||||
|
}
|
||||||
|
.right-fold {
|
||||||
|
position: absolute;
|
||||||
|
display: none;
|
||||||
|
font-weight: bolder;
|
||||||
|
margin-left: 15px;
|
||||||
|
margin-top: -35px;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 1000;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.left-fold {
|
||||||
|
position: absolute;
|
||||||
|
font-weight: bolder;
|
||||||
|
margin-left: -40px;
|
||||||
|
margin-top: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 1000;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.fold:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*拖拽区鼠标悬停样式*/
|
||||||
|
.problem-resize:hover {
|
||||||
|
color: #444444;
|
||||||
|
}
|
||||||
|
.problem-right {
|
||||||
|
height: 100%;
|
||||||
|
float: left;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1080px) {
|
@media screen and (max-width: 1080px) {
|
||||||
.submit-detail {
|
.submit-detail {
|
||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -217,7 +217,7 @@ CREATE TABLE `permissions` (
|
||||||
UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
|
UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
|
||||||
);
|
);
|
||||||
|
|
||||||
insert into `config_info`(`id`,`data_id`,`group_id`,`content`,`md5`,`gmt_create`,`gmt_modified`,`src_user`,`src_ip`,`app_name`,`tenant_id`,`c_desc`,`c_use`,`effect`,`type`,`c_schema`) values (1,'hoj-prod.yml','DEFAULT_GROUP','hoj:\n jwt:\n # 加密秘钥\n secret: hoj-secret-init\n # token默认为24小时 86400s\n expire: 86400\n checkRefreshExpire: 43200\n header: token\n judge:\n # 调用判题服务器的token\n token: hoj-judge-token-init\n db:\n host: 172.20.0.3\n public-host: 172.20.0.3\n port: 3306\n name: hoj\n username: root\n password: hoj123456\n mail:\n ssl: true\n username: your_email_username\n password: your_email_password\n host: smtp.qq.com\n port: 465\n background-img: https://cdn.jsdelivr.net/gh/HimitZH/CDN/images/HCODE.png\n redis:\n host: 172.20.0.2\n port: 6379\n password: hoj123456\n web-config:\n base-url: your_web_url\n name: Hcode Online Judge\n short-name: hoj\n description: Hcode Online Judge\n register: true\n footer:\n record:\n name: 2020-2021\n url: your_record_url\n project:\n name: HOJ\n url: https://gitee.com/himitzh0730/hoj\n hdu:\n account:\n username: \n password: \n cf:\n account:\n username: \n password: ','c83735964d6e700fffa073f3798556a0','2021-05-18 11:29:38','2021-05-18 11:40:41',NULL,'14.211.16.41','','','hoj配置','','','yaml','');
|
insert into `config_info`(`id`,`data_id`,`group_id`,`content`,`md5`,`gmt_create`,`gmt_modified`,`src_user`,`src_ip`,`app_name`,`tenant_id`,`c_desc`,`c_use`,`effect`,`type`,`c_schema`) values (1,'hoj-prod.yml','DEFAULT_GROUP','hoj:\n jwt:\n # 加密秘钥\n secret: hoj-secret-init\n # token默认为24小时 86400s\n expire: 86400\n checkRefreshExpire: 43200\n header: token\n judge:\n # 调用判题服务器的token\n token: hoj-judge-token-init\n db:\n host: 172.20.0.3\n public-host: 172.20.0.3\n port: 3306\n name: hoj\n username: root\n password: hoj123456\n mail:\n ssl: true\n username: your_email_username\n password: your_email_password\n host: smtp.qq.com\n port: 465\n background-img: https://cdn.jsdelivr.net/gh/HimitZH/CDN/images/HCODE.png\n redis:\n host: 172.20.0.2\n port: 6379\n password: hoj123456\n web-config:\n base-url: your_web_url\n name: Hcode Online Judge\n short-name: hoj\n description: Hcode Online Judge\n register: true\n footer:\n record:\n name: 2020-2021\n url: your_record_url\n project:\n name: HOJ\n url: https://gitee.com/himitzh0730/hoj\n hdu:\n account:\n username: \n password: \n cf:\n account:\n username: \n password: \n poj:\n account:\n username: \n password: ','c83735964d6e700fffa073f3798556a0','2021-05-18 11:29:38','2021-05-18 11:40:41',NULL,'14.211.16.41','','','hoj配置','','','yaml','');
|
||||||
|
|
||||||
delete from `users`;
|
delete from `users`;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue