丰富前端操作,增加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-12 | 完善比赛赛制,具体请看在线文档 | 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 | | 是否默认开启该题目的测试样例结果查看 |
|
||||
| caseVersion | String | | 题目测试数据的版本号 |
|
||||
| is_upload_case | boolean | | 是否是上传zip评测数据的 |
|
||||
| modified_user | String | | 最新修改题目的用户 |
|
||||
| gmt_create | datetime | | 创建时间 |
|
||||
| gmt_modified | datetime | | 修改时间 |
|
||||
|
||||
|
@ -529,6 +530,7 @@ discussion表
|
|||
| view_num | int | | 浏览数量 |
|
||||
| like_num | int | | 点赞数量 |
|
||||
| top_priority | boolean | | 优先级,是否置顶 |
|
||||
| comment_num | int | | 评论数量 |
|
||||
| status | int | | 是否封禁或逻辑删除该讨论 |
|
||||
| gmt_create | datetime | | 创建时间 |
|
||||
| gmt_modified | datetime | | 修改时间 |
|
||||
|
|
|
@ -126,6 +126,12 @@
|
|||
<version>5.3.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.vdurmont</groupId>
|
||||
<artifactId>emoji-java</artifactId>
|
||||
<version>4.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<!--redis整合-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
|
|
@ -105,6 +105,12 @@ public class StartupRunner implements CommandLineRunner {
|
|||
@Value("${CF_ACCOUNT_PASSWORD_LIST:}")
|
||||
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}")
|
||||
private String profile;
|
||||
|
||||
|
@ -151,6 +157,10 @@ public class StartupRunner implements CommandLineRunner {
|
|||
|
||||
configVo.setCfUsernameList(cfUsernameList);
|
||||
configVo.setCfPasswordList(cfPasswordList);
|
||||
|
||||
configVo.setPojUsernameList(pojUsernameList);
|
||||
configVo.setPojPasswordList(pojPasswordList);
|
||||
|
||||
configService.sendNewConfigToNacos();
|
||||
|
||||
if (openRemoteJudge.equals("true")) {
|
||||
|
@ -203,6 +213,22 @@ public class StartupRunner implements CommandLineRunner {
|
|||
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()) {
|
||||
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);
|
||||
if (result) { // 更新成功
|
||||
return CommonResult.successResponse(null, "修改成功!");
|
||||
|
|
|
@ -144,7 +144,7 @@ public class AdminProblemController {
|
|||
@RequiresAuthentication
|
||||
@RequiresRoles(value = {"root", "admin", "problem_admin"}, logical = Logical.OR)
|
||||
@Transactional
|
||||
public CommonResult updateProblem(@RequestBody ProblemDto problemDto) {
|
||||
public CommonResult updateProblem(@RequestBody ProblemDto problemDto, HttpServletRequest request) {
|
||||
|
||||
QueryWrapper<Problem> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("problem_id", problemDto.getProblem().getProblemId().toUpperCase());
|
||||
|
@ -154,6 +154,11 @@ public class AdminProblemController {
|
|||
if (problem != null && problem.getId().longValue() != problemDto.getProblem().getId()) {
|
||||
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);
|
||||
if (result) { // 更新成功
|
||||
|
|
|
@ -12,13 +12,16 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
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.CommentLike;
|
||||
import top.hcode.hoj.pojo.entity.Discussion;
|
||||
import top.hcode.hoj.pojo.entity.Reply;
|
||||
import top.hcode.hoj.pojo.vo.CommentsVo;
|
||||
import top.hcode.hoj.pojo.vo.UserRolesVo;
|
||||
import top.hcode.hoj.service.impl.CommentLikeServiceImpl;
|
||||
import top.hcode.hoj.service.impl.CommentServiceImpl;
|
||||
import top.hcode.hoj.service.impl.DiscussionServiceImpl;
|
||||
import top.hcode.hoj.service.impl.ReplyServiceImpl;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -45,6 +48,9 @@ public class CommentController {
|
|||
@Autowired
|
||||
private ReplyServiceImpl replyService;
|
||||
|
||||
@Autowired
|
||||
private DiscussionServiceImpl discussionService;
|
||||
|
||||
|
||||
@GetMapping("/comments")
|
||||
public CommonResult getComments(@RequestParam(value = "cid", required = false) Long cid,
|
||||
|
@ -126,6 +132,13 @@ public class CommentController {
|
|||
commentsVo.setLikeNum(0);
|
||||
commentsVo.setGmtCreate(comment.getGmtCreate());
|
||||
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, "评论成功");
|
||||
} else {
|
||||
return CommonResult.errorResponse("评论失败,请重新尝试!");
|
||||
|
@ -151,6 +164,13 @@ public class CommentController {
|
|||
replyService.remove(new UpdateWrapper<Reply>().eq("comment_id", comment.getId()));
|
||||
|
||||
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, "删除成功");
|
||||
} else {
|
||||
return CommonResult.errorResponse("删除失败,请重新尝试");
|
||||
|
@ -222,11 +242,11 @@ public class CommentController {
|
|||
@PostMapping("/reply")
|
||||
@RequiresPermissions("reply_add")
|
||||
@RequiresAuthentication
|
||||
public CommonResult addReply(@RequestBody Reply reply, HttpServletRequest request) {
|
||||
public CommonResult addReply(@RequestBody ReplyDto replyDto, HttpServletRequest request) {
|
||||
// 获取当前登录的用户
|
||||
HttpSession session = request.getSession();
|
||||
UserRolesVo userRolesVo = (UserRolesVo) session.getAttribute("userInfo");
|
||||
|
||||
Reply reply = replyDto.getReply();
|
||||
reply.setFromAvatar(userRolesVo.getAvatar())
|
||||
.setFromName(userRolesVo.getUsername())
|
||||
.setFromUid(userRolesVo.getUid());
|
||||
|
@ -244,6 +264,13 @@ public class CommentController {
|
|||
boolean isOk = replyService.saveOrUpdate(reply);
|
||||
|
||||
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, "评论成功");
|
||||
} else {
|
||||
return CommonResult.errorResponse("评论失败,请重新尝试!");
|
||||
|
@ -252,19 +279,24 @@ public class CommentController {
|
|||
|
||||
@DeleteMapping("/reply")
|
||||
@RequiresAuthentication
|
||||
public CommonResult deleteReply(@RequestBody Reply reply, HttpServletRequest request) {
|
||||
public CommonResult deleteReply(@RequestBody ReplyDto replyDto, HttpServletRequest request) {
|
||||
// 获取当前登录的用户
|
||||
HttpSession session = request.getSession();
|
||||
UserRolesVo userRolesVo = (UserRolesVo) session.getAttribute("userInfo");
|
||||
|
||||
Reply reply = replyDto.getReply();
|
||||
// 如果不是评论本人 或者不是管理员 无权限删除该评论
|
||||
if (reply.getFromUid().equals(userRolesVo.getUid()) || SecurityUtils.getSubject().hasRole("root")
|
||||
|| SecurityUtils.getSubject().hasRole("admin") || SecurityUtils.getSubject().hasRole("problem_admin")) {
|
||||
|
||||
// 删除该数据
|
||||
boolean isOk = replyService.removeById(reply.getId());
|
||||
|
||||
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, "删除成功");
|
||||
} else {
|
||||
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:}")
|
||||
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.StringUtils;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import top.hcode.hoj.crawler.problem.CFProblemStrategy;
|
||||
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.crawler.problem.*;
|
||||
import top.hcode.hoj.pojo.dto.ProblemDto;
|
||||
import top.hcode.hoj.pojo.entity.*;
|
||||
import top.hcode.hoj.pojo.vo.ImportProblemVo;
|
||||
|
@ -544,6 +541,9 @@ public class ProblemServiceImpl extends ServiceImpl<ProblemMapper, Problem> impl
|
|||
case "CF":
|
||||
problemStrategy = new CFProblemStrategy();
|
||||
break;
|
||||
case "POJ":
|
||||
problemStrategy = new POJProblemStrategy();
|
||||
break;
|
||||
default:
|
||||
throw new Exception("未知的OJ的名字,暂时不支持!");
|
||||
}
|
||||
|
|
|
@ -72,7 +72,11 @@ public class ConfigUtils {
|
|||
" cf:\n" +
|
||||
" account:\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) {
|
||||
|
|
|
@ -58,7 +58,8 @@ public class Constants {
|
|||
|
||||
public enum RemoteOJ {
|
||||
HDU("HDU"),
|
||||
CODEFORCES("CF");
|
||||
CODEFORCES("CF"),
|
||||
POJ("POJ");
|
||||
|
||||
private final String name;
|
||||
|
||||
|
|
|
@ -32,8 +32,7 @@ public class RemoteJudgeGetResult {
|
|||
|
||||
@Transactional
|
||||
public void sendTask(String remoteJudge, String username, Long submitId, String uid,
|
||||
Long cid, Long pid, Long resultSubmitId, String token,
|
||||
HashMap<String, String> cookies) {
|
||||
Long cid, Long pid, Long resultSubmitId, String cookies) {
|
||||
|
||||
RemoteJudgeStrategy remoteJudgeStrategy = RemoteJudgeFactory.selectJudge(remoteJudge);
|
||||
|
||||
|
@ -47,7 +46,7 @@ public class RemoteJudgeGetResult {
|
|||
public void run() {
|
||||
count.getAndIncrement();
|
||||
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());
|
||||
if (status.intValue() != Constants.Judge.STATUS_PENDING.getStatus() &&
|
||||
status.intValue() != Constants.Judge.STATUS_JUDGING.getStatus()) {
|
||||
|
|
|
@ -87,17 +87,16 @@ public class RemoteJudgeToSubmit {
|
|||
return;
|
||||
}
|
||||
|
||||
// 提交成功顺便更新状态为-->STATUS_JUDGING 判题中...
|
||||
// 提交成功顺便更新状态为-->STATUS_PENDING 等待中...
|
||||
judgeService.updateById(new Judge()
|
||||
.setSubmitId(submitId)
|
||||
.setStatus(Constants.Judge.STATUS_JUDGING.getStatus())
|
||||
.setStatus(Constants.Judge.STATUS_PENDING.getStatus())
|
||||
.setJudger(name)
|
||||
);
|
||||
|
||||
// 调用获取远程判题结果
|
||||
remoteJudgeGetResult.sendTask(remoteJudge, username, submitId, uid, cid, pid,
|
||||
(Long) submitResult.get("runId"), (String) submitResult.get("token"),
|
||||
(HashMap<String, String>) submitResult.get("cookies"));
|
||||
(Long) submitResult.get("runId"), (String) submitResult.get("cookies"));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ import com.gargoylesoftware.htmlunit.SilentCssErrorHandler;
|
|||
import com.gargoylesoftware.htmlunit.WebClient;
|
||||
import com.gargoylesoftware.htmlunit.html.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jsoup.Connection;
|
||||
import top.hcode.hoj.remoteJudge.task.RemoteJudgeStrategy;
|
||||
import top.hcode.hoj.util.Constants;
|
||||
|
||||
|
@ -73,16 +72,15 @@ public class CodeForcesJudge implements RemoteJudgeStrategy {
|
|||
|
||||
// 获取提交的题目id
|
||||
|
||||
Long maxRunId = getMaxRunId(null, username, problemId);
|
||||
Long maxRunId = getMaxRunId(username, problemId);
|
||||
|
||||
return MapUtil.builder(new HashMap<String, Object>())
|
||||
.put("runId", maxRunId)
|
||||
.put("token", "")
|
||||
.put("cookies", new HashMap<String, String>())
|
||||
.put("cookies", null)
|
||||
.map();
|
||||
}
|
||||
|
||||
private Long getMaxRunId(Connection connection, String username, String problemId) throws InterruptedException {
|
||||
private Long getMaxRunId(String username, String problemId) throws InterruptedException {
|
||||
int retryNum = 0;
|
||||
String url = String.format(SUBMISSION_RESULT_URL, username);
|
||||
HttpRequest httpRequest = HttpUtil.createGet(HOST + url);
|
||||
|
@ -118,7 +116,7 @@ public class CodeForcesJudge implements RemoteJudgeStrategy {
|
|||
}
|
||||
|
||||
@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);
|
||||
|
||||
|
|
|
@ -2,15 +2,13 @@ package top.hcode.hoj.remoteJudge.task.Impl;
|
|||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ReUtil;
|
||||
import cn.hutool.http.HtmlUtil;
|
||||
import cn.hutool.http.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jsoup.Connection;
|
||||
|
||||
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.util.Constants;
|
||||
import top.hcode.hoj.util.JsoupUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -31,6 +29,7 @@ public class HduJudge implements RemoteJudgeStrategy {
|
|||
.put("Host", "acm.hdu.edu.cn")
|
||||
.put("origin", "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();
|
||||
|
||||
/**
|
||||
|
@ -45,39 +44,46 @@ public class HduJudge implements RemoteJudgeStrategy {
|
|||
return null;
|
||||
}
|
||||
Map<String, Object> loginUtils = getLoginUtils(username, password);
|
||||
Map<String, String> loginCookie = (Map<String, String>) loginUtils.get("cookie");
|
||||
Connection connection = JsoupUtils.getConnectionFromUrl(HOST + SUBMIT_URL, headers, loginCookie);
|
||||
Connection.Response response = JsoupUtils.postResponse(connection, MapUtil
|
||||
.builder(new HashMap<String, String>())
|
||||
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("check", "0")
|
||||
.put("language", getLanguage(language))
|
||||
.put("problemid", problemId)
|
||||
.put("usercode", userCode)
|
||||
.map());
|
||||
if (response.statusCode() != 200) {
|
||||
.map())
|
||||
.execute();
|
||||
if (response.getStatus() != 200) {
|
||||
log.error("进行题目提交时发生错误:提交题目失败," + HduJudge.class.getName() + ",题号:" + problemId);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 下面的请求都是GET
|
||||
request.setMethod(Method.GET);
|
||||
// 获取提交的题目id
|
||||
Long maxRunId = getMaxRunId(connection, username, problemId);
|
||||
Long maxRunId = getMaxRunId(request, username, problemId);
|
||||
|
||||
if (maxRunId == -1L) { // 等待2s再次查询,如果还是失败,则表明提交失败了
|
||||
TimeUnit.SECONDS.sleep(2);
|
||||
maxRunId = getMaxRunId(connection, username, problemId);
|
||||
maxRunId = getMaxRunId(request, username, problemId);
|
||||
}
|
||||
return MapUtil.builder(new HashMap<String, Object>())
|
||||
.put("token", null)
|
||||
.put("cookies", loginCookie)
|
||||
.put("cookies", cookies)
|
||||
.put("runId", maxRunId)
|
||||
.map();
|
||||
}
|
||||
|
||||
@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);
|
||||
Connection connection = JsoupUtils.getConnectionFromUrl(url, headers, null);
|
||||
Connection.Response response = JsoupUtils.getResponse(connection, null);
|
||||
HttpRequest request = HttpUtil.createGet(url)
|
||||
.cookie(cookies)
|
||||
.addHeaders(headers);
|
||||
HttpResponse response = request.execute();
|
||||
// 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>");
|
||||
|
@ -100,9 +106,9 @@ public class HduJudge implements RemoteJudgeStrategy {
|
|||
result.put("memory", Integer.parseInt(executionMemory));
|
||||
// 如果CE了,则还需要获得错误信息
|
||||
if (statusType == Constants.Judge.STATUS_COMPILE_ERROR) {
|
||||
connection.url(HOST + String.format(ERROR_URL, submitId));
|
||||
response = JsoupUtils.getResponse(connection, null);
|
||||
String compilationErrorInfo = ReUtil.get("<pre>([\\s\\S]*?)</pre>", response.body(), 1);
|
||||
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));
|
||||
}
|
||||
return result;
|
||||
|
@ -110,14 +116,16 @@ public class HduJudge implements RemoteJudgeStrategy {
|
|||
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getLoginUtils(String username, String password) throws Exception {
|
||||
Connection connection = JsoupUtils.getConnectionFromUrl(HOST + LOGIN_URL, headers, null);
|
||||
Connection.Response response = JsoupUtils.postResponse(connection, MapUtil
|
||||
.builder(new HashMap<String, String>())
|
||||
public Map<String, Object> getLoginUtils(String username, String password){
|
||||
|
||||
HttpRequest request = HttpUtil.createPost(HOST + LOGIN_URL).addHeaders(headers);
|
||||
HttpResponse response = request.form(MapUtil
|
||||
.builder(new HashMap<String, Object>())
|
||||
.put("username", username)
|
||||
.put("login", "Sign In")
|
||||
.put("userpass", password).map());
|
||||
return MapUtil.builder(new HashMap<String, Object>()).put("cookie", response.cookies()).map();
|
||||
.put("userpass", password).map())
|
||||
.execute();
|
||||
return MapUtil.builder(new HashMap<String, Object>()).put("cookie", response.getCookieStr()).map();
|
||||
}
|
||||
|
||||
@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);
|
||||
connection.url(HOST + url);
|
||||
Connection.Response response = JsoupUtils.getResponse(connection, null);
|
||||
HttpResponse response = request.setUrl(url).execute();
|
||||
Matcher matcher = Pattern.compile("<td height=22px>(\\d+)").matcher(response.body());
|
||||
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.HduJudge;
|
||||
import top.hcode.hoj.remoteJudge.task.Impl.POJJudge;
|
||||
import top.hcode.hoj.util.Constants;
|
||||
|
||||
|
||||
|
@ -14,6 +15,8 @@ public class RemoteJudgeFactory {
|
|||
return new HduJudge();
|
||||
case CF_JUDGE:
|
||||
return new CodeForcesJudge();
|
||||
case POJ_JUDGE:
|
||||
return new POJJudge();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ public interface RemoteJudgeStrategy {
|
|||
* @param username 题库的提交者的账号
|
||||
* @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;
|
||||
|
||||
|
|
|
@ -67,6 +67,8 @@ public class Constants {
|
|||
|
||||
CF_JUDGE("CF"),
|
||||
|
||||
POJ_JUDGE("POJ"),
|
||||
|
||||
HDU_REMOTE_JUDGE_ACCOUNT("Hdu Remote Judge Account"),
|
||||
|
||||
CF_REMOTE_JUDGE_ACCOUNT("Codeforces Remote Judge Account");
|
||||
|
|
|
@ -88,4 +88,6 @@ public class JudgeServerApplicationTests {
|
|||
"}");
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -56,7 +56,10 @@ public class Discussion {
|
|||
private Integer viewNum;
|
||||
|
||||
@ApiModelProperty(value = "点赞数量")
|
||||
private String likeNum;
|
||||
private Integer likeNum;
|
||||
|
||||
@ApiModelProperty(value = "评论数量,包括其评论及其回复数")
|
||||
private Integer commentNum;
|
||||
|
||||
@ApiModelProperty(value = "优先级,是否置顶")
|
||||
private Boolean topPriority;
|
||||
|
|
|
@ -45,7 +45,7 @@ public class Problem implements Serializable {
|
|||
@ApiModelProperty(value = "单位ms")
|
||||
private Integer timeLimit;
|
||||
|
||||
@ApiModelProperty(value = "单位kb")
|
||||
@ApiModelProperty(value = "单位mb")
|
||||
private Integer memoryLimit;
|
||||
|
||||
@ApiModelProperty(value = "单位mb")
|
||||
|
@ -104,6 +104,9 @@ public class Problem implements Serializable {
|
|||
@ApiModelProperty(value = "题目测试数据的版本号")
|
||||
private String caseVersion;
|
||||
|
||||
@ApiModelProperty(value = "修改题目的管理员用户名")
|
||||
private String modifiedUser;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date gmtCreate;
|
||||
|
||||
|
|
|
@ -151,7 +151,8 @@ export const PROBLEM_LEVEL_RESERVE={
|
|||
|
||||
export const REMOTE_OJ = [
|
||||
{name:'HDU',key:"HDU"},
|
||||
{name:"Codeforces",key:"CF"}
|
||||
{name:"Codeforces",key:"CF"},
|
||||
{name:"POJ",key:"POJ"},
|
||||
]
|
||||
|
||||
export const CONTEST_STATUS = {
|
||||
|
|
|
@ -622,7 +622,10 @@ export default {
|
|||
return;
|
||||
}
|
||||
this.replyObj.content = this.replyInputComment;
|
||||
let replyData = Object.assign({}, this.replyObj);
|
||||
let replyData = {
|
||||
reply: this.replyObj,
|
||||
did: this.did,
|
||||
};
|
||||
api.addReply(replyData).then((res) => {
|
||||
for (let i = 0; i < this.comments.length; i++) {
|
||||
if (this.comments[i].id == this.replyObj.commentId) {
|
||||
|
@ -715,6 +718,7 @@ export default {
|
|||
.then(() => {
|
||||
let replyDeleteData = {
|
||||
id: reply.id,
|
||||
did: this.did,
|
||||
fromUid: reply.fromUid,
|
||||
};
|
||||
api.deleteReply(replyDeleteData).then((res) => {
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<template>
|
||||
<div style="margin: 0px 0px 15px 0px;font-size: 14px;">
|
||||
<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">
|
||||
<span>{{ $t('m.Lang') }}:</span>
|
||||
<span>
|
||||
<el-select
|
||||
:value="this.language"
|
||||
@change="onLangChange"
|
||||
class="adjust"
|
||||
class="left-adjust"
|
||||
size="small"
|
||||
>
|
||||
<el-option v-for="item in languages" :key="item" :value="item"
|
||||
|
@ -44,13 +44,13 @@
|
|||
</span>
|
||||
</div>
|
||||
</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">
|
||||
<span>{{ $t('m.Theme') }}:</span>
|
||||
<el-select
|
||||
:value="this.theme"
|
||||
@change="onThemeChange"
|
||||
class="adjust"
|
||||
class="right-adjust"
|
||||
size="small"
|
||||
>
|
||||
<el-option
|
||||
|
@ -104,6 +104,7 @@ import 'codemirror/mode/php/php.js'; //php
|
|||
import 'codemirror/mode/ruby/ruby.js'; //ruby
|
||||
import 'codemirror/mode/rust/rust.js'; //rust
|
||||
import 'codemirror/mode/javascript/javascript.js'; //javascript
|
||||
import 'codemirror/mode/fortran/fortran.js'; //fortran
|
||||
|
||||
// active-line.js
|
||||
import 'codemirror/addon/selection/active-line.js';
|
||||
|
@ -260,10 +261,15 @@ export default {
|
|||
margin-right: 5px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
.header .adjust {
|
||||
.header .left-adjust {
|
||||
width: 170px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
.header .right-adjust {
|
||||
width: 140px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.select-row {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
|
|
@ -126,6 +126,7 @@ export const m = {
|
|||
Add_Rmote_OJ_Problem:'Add Remote OJ Problem',
|
||||
Add_From_Public_Problem:'Add From Public Problem',
|
||||
Auth:'Auth',
|
||||
Modified_User:'Modified User',
|
||||
Public_Problem:'Public Problem',
|
||||
Private_Problem:'Private Problem',
|
||||
Contest_Problem:'Contest Problem',
|
||||
|
|
|
@ -126,6 +126,7 @@ export const m = {
|
|||
Add_Rmote_OJ_Problem:'添加远程OJ题目',
|
||||
Add_From_Public_Problem:'从公共题库添加题目',
|
||||
Auth:'权限',
|
||||
Modified_User:'最近修改者',
|
||||
Public_Problem:'公开题目',
|
||||
Private_Problem:'隐藏题目',
|
||||
Contest_Problem:'比赛题目',
|
||||
|
|
|
@ -164,6 +164,10 @@ export const m = {
|
|||
Good_luck_to_you:'Good luck to you!',
|
||||
|
||||
// /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',
|
||||
Show_Tags:'Show tags',
|
||||
No_tag:'No tag',
|
||||
|
|
|
@ -165,6 +165,10 @@ export const m = {
|
|||
Good_luck_to_you:'祝你好运!',
|
||||
|
||||
// /views/oj/problem/Problem.vue
|
||||
Shrink_Sidebar:'收缩侧边栏',
|
||||
View_Problem_Content:'查看题目内容',
|
||||
Only_View_Problem:'只看题目内容',
|
||||
Put_away_the_full_screen_and_write_the_code:'收起全屏,编写代码',
|
||||
Contest_Problem:'比赛题目',
|
||||
Show_Tags:'显示标签',
|
||||
No_tag:'暂无标签',
|
||||
|
@ -243,7 +247,7 @@ export const m = {
|
|||
OI_Ranklist: 'OI 排行榜',
|
||||
|
||||
// /views/oj/discussion/discussionList.vue
|
||||
Created_Time:'创建时间',
|
||||
Created_Time:'发布时间',
|
||||
Likes:'点赞',
|
||||
Views:'浏览',
|
||||
Edit:'编辑',
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
</vxe-table-column>
|
||||
<vxe-table-column
|
||||
field="author"
|
||||
min-width="150"
|
||||
min-width="130"
|
||||
:title="$t('m.Author')"
|
||||
>
|
||||
</vxe-table-column>
|
||||
|
@ -73,6 +73,12 @@
|
|||
{{ row.gmtCreate | localtime }}
|
||||
</template>
|
||||
</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')">
|
||||
<template v-slot="{ row }">
|
||||
<el-select
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
{{ discussion.title }}
|
||||
</h1>
|
||||
</a>
|
||||
|
||||
<a
|
||||
@click="toDiscussionDetail(discussion.id)"
|
||||
class="article-hlink2"
|
||||
|
@ -101,30 +102,30 @@
|
|||
>ADM</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>
|
||||
{{ $t('m.Created_Time') }}:<el-tooltip
|
||||
:content="discussion.gmtCreate | localtime"
|
||||
placement="top"
|
||||
>
|
||||
<span>{{ discussion.gmtCreate | fromNow }}</span>
|
||||
</el-tooltip></span
|
||||
<span class="hidden-xs-only"> {{ $t('m.Comment') }}:</span>
|
||||
{{ discussion.commentNum }}</span
|
||||
></span
|
||||
>
|
||||
|
||||
<span class="pr"
|
||||
><label class="fw"><i class="fa fa-thumbs-o-up"></i></label
|
||||
><span>
|
||||
{{ $t('m.Likes') }}:{{ discussion.likeNum }}</span
|
||||
<span class="hidden-xs-only"> {{ $t('m.Likes') }}:</span>
|
||||
{{ discussion.likeNum }}</span
|
||||
></span
|
||||
>
|
||||
<span class="pr"
|
||||
><label class="fw"><i class="fa fa-eye"></i></label
|
||||
><span>
|
||||
{{ $t('m.Views') }}:{{ discussion.viewNum }}</span
|
||||
<span class="hidden-xs-only"> {{ $t('m.Views') }}:</span>
|
||||
{{ discussion.viewNum }}</span
|
||||
></span
|
||||
>
|
||||
<span
|
||||
<span class="pr"
|
||||
><label class="fw"><i class="el-icon-folder-opened"></i></label>
|
||||
<a
|
||||
@click="
|
||||
|
@ -139,6 +140,18 @@
|
|||
>
|
||||
</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
|
||||
style="float:right;"
|
||||
class="hidden-xs-only"
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
<div>
|
||||
<div id="problem-main">
|
||||
<!--problem main-->
|
||||
<el-row>
|
||||
<el-col :sm="24" :md="24" :lg="12">
|
||||
<el-row class="problem-box">
|
||||
<el-col :sm="24" :md="24" :lg="12" class="problem-left">
|
||||
<el-card :padding="10" shadow class="problem-detail">
|
||||
<div slot="header" class="panel-title">
|
||||
<span>{{ problemData.problem.title }}</span
|
||||
|
@ -172,7 +172,42 @@
|
|||
</div>
|
||||
</el-card>
|
||||
</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
|
||||
:padding="10"
|
||||
id="submit-code"
|
||||
|
@ -432,6 +467,8 @@ export default {
|
|||
JUDGE_STATUS_RESERVE: {},
|
||||
PROBLEM_LEVEL: {},
|
||||
RULE_TYPE: {},
|
||||
toResetWatch: false,
|
||||
toWatchProblem: false,
|
||||
};
|
||||
},
|
||||
// 获取缓存中的该题的做题代码,代码语言,代码风格
|
||||
|
@ -449,6 +486,7 @@ export default {
|
|||
next();
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.JUDGE_STATUS_RESERVE = Object.assign({}, JUDGE_STATUS_RESERVE);
|
||||
this.PROBLEM_LEVEL = Object.assign({}, PROBLEM_LEVEL);
|
||||
|
@ -456,9 +494,95 @@ export default {
|
|||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
this.dragControllerDiv();
|
||||
},
|
||||
methods: {
|
||||
...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() {
|
||||
if (this.$route.params.contestID) {
|
||||
this.contestID = this.$route.params.contestID;
|
||||
|
@ -890,6 +1014,7 @@ export default {
|
|||
#problem-main {
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
.problem-menu {
|
||||
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) {
|
||||
.submit-detail {
|
||||
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
|
||||
);
|
||||
|
||||
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`;
|
||||
|
||||
|
|
Loading…
Reference in New Issue