增加Codeforces的题目爬取

This commit is contained in:
Himit_ZH 2021-03-03 21:22:41 +08:00
parent 1b10850be6
commit 535d10ab6e
30 changed files with 460 additions and 75 deletions

View File

@ -81,6 +81,7 @@
| 2021-02-20 | 测试HDU判题整套流程完成 | Himit_ZH |
| 2021-02-22 | 修改前端编辑器样式以及md格式转换 | Himit_ZH |
| 2021-02-24 | 完善测试比赛相关接口,验证权限及数据计算 | Himit_ZH |
| 2021-03-03 | 增加Codeforces的题目爬取 | Himit_ZH |
# 二、系统架构

View File

@ -13,6 +13,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import top.hcode.hoj.common.result.CommonResult;
import top.hcode.hoj.crawler.problem.ProblemStrategy;
import top.hcode.hoj.pojo.dto.ProblemDto;
import top.hcode.hoj.pojo.entity.*;
import top.hcode.hoj.pojo.vo.UserRolesVo;
@ -41,9 +42,6 @@ public class AdminProblemController {
@Autowired
private ProblemCaseServiceImpl problemCaseService;
@Autowired
private ContestProblemServiceImpl contestProblemService;
@Autowired
private ToJudgeService toJudgeService;
@ -186,6 +184,7 @@ public class AdminProblemController {
@GetMapping("/import-remote-oj-problem")
@RequiresAuthentication
@RequiresRoles(value = {"root", "admin"}, logical = Logical.OR)
@Transactional
public CommonResult importRemoteOJProblem(@RequestParam("name") String name,
@RequestParam("problemId") String problemId,
HttpServletRequest request) {
@ -200,14 +199,14 @@ public class AdminProblemController {
HttpSession session = request.getSession();
UserRolesVo userRolesVo = (UserRolesVo) session.getAttribute("userInfo");
try {
Problem otherOJProblemInfo = problemService.getOtherOJProblemInfo(name.toUpperCase(), problemId, userRolesVo.getUsername());
ProblemStrategy.RemoteProblemInfo otherOJProblemInfo = problemService.getOtherOJProblemInfo(name.toUpperCase(), problemId, userRolesVo.getUsername());
if (otherOJProblemInfo != null) {
boolean result = problemService.adminAddOtherOJProblem(otherOJProblemInfo, name);
if (!result) {
return CommonResult.errorResponse("导入新题目失败!请重新尝试!");
}
} else {
return CommonResult.errorResponse("导入新题目失败原因获取该OJ的题目数据失败");
return CommonResult.errorResponse("导入新题目失败原因获取该OJ的题目数据失败可能是链接超时!");
}
} catch (Exception e) {
return CommonResult.errorResponse(e.getMessage());

View File

@ -253,21 +253,27 @@ public class ContestController {
}
//查询题目详情题目标签题目语言题目做题情况
Problem problem = problemService.getById(contestProblem.getPid());
QueryWrapper<ProblemTag> problemTagQueryWrapper = new QueryWrapper<>();
problemTagQueryWrapper.eq("pid", contestProblem.getPid());
// 获取该题号对应的标签id
List<Long> tidList = new LinkedList<>();
problemTagService.list(problemTagQueryWrapper).forEach(problemTag -> {
tidList.add(problemTag.getTid());
});
List<String> tagsStr = new LinkedList<>();
if (tidList.size() != 0) {
tagService.listByIds(tidList).forEach(tag -> {
tagsStr.add(tag.getName());
// 比赛结束后才开放标签和source
if (contest.getStatus().intValue() != Constants.Contest.STATUS_ENDED.getCode()) {
problem.setSource(null);
QueryWrapper<ProblemTag> problemTagQueryWrapper = new QueryWrapper<>();
problemTagQueryWrapper.eq("pid", contestProblem.getPid());
// 获取该题号对应的标签id
List<Long> tidList = new LinkedList<>();
problemTagService.list(problemTagQueryWrapper).forEach(problemTag -> {
tidList.add(problemTag.getTid());
});
if (tidList.size() != 0) {
tagService.listByIds(tidList).forEach(tag -> {
tagsStr.add(tag.getName());
});
}
}
// 获取题目提交的代码支持的语言
List<String> languagesStr = new LinkedList<>();
QueryWrapper<ProblemLanguage> problemLanguageQueryWrapper = new QueryWrapper<>();

View File

@ -0,0 +1,92 @@
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.StringUtils;
import top.hcode.hoj.pojo.entity.Problem;
import top.hcode.hoj.pojo.entity.Tag;
import top.hcode.hoj.utils.JsoupUtils;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;
/**
* @Author: Himit_ZH
* @Date: 2021/3/3 15:00
* @Description:
*/
public class CFProblemStrategy extends ProblemStrategy {
public static final String JUDGE_NAME = "CF";
public static final String HOST = "https://codeforces.com";
public static final String PROBLEM_URL = "/problemset/problem/%s/%s";
@Override
public RemoteProblemInfo getProblemInfo(String problemId, String author) throws Exception {
String contestId = ReUtil.get("([0-9]+)[A-Z]{1}[0-9]{0,1}", problemId, 1);
String problemNum = ReUtil.get("[0-9]+([A-Z]{1}[0-9]{0,1})", problemId, 1);
if (contestId == null || problemNum == null) {
throw new Exception("Codeforces的题号格式错误");
}
String url = HOST + String.format(PROBLEM_URL, contestId, problemNum);
Connection connection = JsoupUtils.getConnectionFromUrl(url, null, null);
Document document = JsoupUtils.getDocument(connection, null);
String html = document.html();
Problem info = new Problem();
info.setProblemId(JUDGE_NAME + "-" + problemId);
info.setTitle(ReUtil.get("<div class=\"title\">\\s*" + problemNum + "\\. ([\\s\\S]*?)</div>", html, 1).trim());
info.setTimeLimit(1000 * Integer.parseInt(ReUtil.get("</div>([\\d\\.]+) (seconds?|s)\\s*</div>", html, 1)));
info.setMemoryLimit(Integer.parseInt(ReUtil.get("</div>(\\d+) (megabytes|MB)\\s*</div>", html, 1)));
String tmpDesc = ReUtil.get("standard output\\s*</div></div><div>([\\s\\S]*?)</div><div class=\"input-specification",
html, 1);
if (StringUtils.isEmpty(tmpDesc)) {
tmpDesc = ReUtil.get("<div class=\"input-file\">([\\s\\S]*?)</div><div class=\"input-specification", html, 1);
}
info.setDescription(tmpDesc.replaceAll("\\$\\$\\$","\\$").replaceAll("src=\"../../", "src=\"" + HOST + "/"));
info.setInput(ReUtil.get("<div class=\"section-title\">\\s*Input\\s*</div>([\\s\\S]*?)</div><div class=\"output-specification\">", html, 1).replaceAll("\\$\\$\\$","\\$"));
info.setOutput(ReUtil.get("<div class=\"section-title\">\\s*Output\\s*</div>([\\s\\S]*?)</div><div class=\"sample-tests\">", html, 1).replaceAll("\\$\\$\\$","\\$"));
StringBuilder sb = new StringBuilder("<input>");
sb.append(ReUtil.get("<div class=\"sample-test\"><div class=\"input\"><div class=\"title\">Input</div><pre>([\\s\\S]*?)</pre></div>", html, 1));
sb.append("</input><output>");
sb.append(ReUtil.get("<div class=\"output\"><div class=\"title\">Output</div><pre>([\\s\\S]*?)</pre></div></div>", html, 1)).append("</output>");
info.setExamples(sb.toString());
info.setHint(ReUtil.get("<div class=\"section-title\">\\s*Note\\s*</div>([\\s\\S]*?)</div></div>", html, 1).replaceAll("\\$\\$\\$","\\$"));
info.setIsRemote(true);
info.setSource(String.format("<p>Problem<a style='color:#1A5CC8' href='https://codeforces.com/problemset/problem/%s/%s'>%s</a></p><p>" +
"Contest" + ReUtil.get("(<a[^<>]+/contest/\\d+\">.+?</a>)", html, 1).replace("/contest", HOST + "/contest")
.replace("color: black", "color: #009688;") + "</p>",
contestId, problemNum, JUDGE_NAME + "-" + problemId));
info.setType(0)
.setAuth(1)
.setAuthor(author)
.setOpenCaseResult(false)
.setIsRemoveEndBlank(false)
.setDifficulty(1); // 默认为中等
List<String> all = ReUtil.findAll(Pattern.compile("<span class=\"tag-box\" style=\"font-size:1\\.2rem;\" title=\"[\\s\\S]*?\">([\\s\\S]*?)</span>"), html, 1);
List<Tag> tagList = new LinkedList<>();
for (String tmp:all){
tagList.add(new Tag().setName(tmp.trim()));
}
return new RemoteProblemInfo().setProblem(info).setTagList(tagList);
}
}

View File

@ -4,6 +4,7 @@ import cn.hutool.core.util.ReUtil;
import org.jsoup.Connection;
import org.jsoup.helper.Validate;
import org.jsoup.nodes.Document;
import org.springframework.util.Assert;
import top.hcode.hoj.pojo.entity.Problem;
import top.hcode.hoj.utils.JsoupUtils;
@ -24,9 +25,9 @@ public class HDUProblemStrategy extends ProblemStrategy {
* @throws Exception
*/
@Override
public Problem getProblemInfo(String problemId, String author) throws Exception {
public RemoteProblemInfo getProblemInfo(String problemId, String author) throws Exception {
// 验证题号是否符合规范
Validate.isTrue(problemId.matches("[1-9]\\d*"));
Assert.isTrue(problemId.matches("[1-9]\\d*"),"HDU题号格式错误");
Problem info = new Problem();
String url = HOST + String.format(PROBLEM_URL, problemId);
Connection connection = JsoupUtils.getConnectionFromUrl(url, null, null);
@ -52,7 +53,8 @@ public class HDUProblemStrategy extends ProblemStrategy {
.setAuthor(author)
.setOpenCaseResult(false)
.setIsRemoveEndBlank(false)
.setDifficulty(0); // 默认为简单
return info;
.setDifficulty(1); // 默认为简单
return new RemoteProblemInfo().setProblem(info).setTagList(null);
}
}

View File

@ -18,11 +18,10 @@ public class ProblemContext {
}
//上下文接口
public Problem getProblemInfo(String problemId, String author) {
Problem problem;
public ProblemStrategy.RemoteProblemInfo getProblemInfo(String problemId, String author) {
try {
problem = problemStrategy.getProblemInfo(problemId, author);
return problem;
return problemStrategy.getProblemInfo(problemId, author);
} catch (Exception e) {
log.error("获取题目详情失败---------------->{}", e.getMessage());
}

View File

@ -1,8 +1,21 @@
package top.hcode.hoj.crawler.problem;
import lombok.Data;
import lombok.experimental.Accessors;
import top.hcode.hoj.pojo.entity.Problem;
import top.hcode.hoj.pojo.entity.Tag;
import java.util.List;
public abstract class ProblemStrategy {
public abstract Problem getProblemInfo(String problemId,String author) throws Exception;
public abstract RemoteProblemInfo getProblemInfo(String problemId,String author) throws Exception;
@Data
@Accessors(chain = true)
public static
class RemoteProblemInfo {
private Problem problem;
private List<Tag> tagList;
}
}

View File

@ -1,6 +1,7 @@
package top.hcode.hoj.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import top.hcode.hoj.crawler.problem.ProblemStrategy;
import top.hcode.hoj.pojo.dto.ProblemDto;
import top.hcode.hoj.pojo.vo.ProblemVo;
import top.hcode.hoj.pojo.entity.Problem;
@ -25,7 +26,7 @@ public interface ProblemService extends IService<Problem> {
boolean adminAddProblem(ProblemDto problemDto);
Problem getOtherOJProblemInfo(String OJName, String problemId, String author) throws Exception;
ProblemStrategy.RemoteProblemInfo getOtherOJProblemInfo(String OJName, String problemId, String author) throws Exception;
boolean adminAddOtherOJProblem(Problem problem,String OJName);
boolean adminAddOtherOJProblem(ProblemStrategy.RemoteProblemInfo remoteProblemInfo,String OJName);
}

View File

@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import top.hcode.hoj.common.result.CommonResult;
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;
@ -377,7 +378,7 @@ public class ProblemServiceImpl extends ServiceImpl<ProblemMapper, Problem> impl
}
@Override
public Problem getOtherOJProblemInfo(String OJName, String problemId, String author) throws Exception {
public ProblemStrategy.RemoteProblemInfo getOtherOJProblemInfo(String OJName, String problemId, String author) throws Exception {
ProblemStrategy problemStrategy;
@ -385,6 +386,9 @@ public class ProblemServiceImpl extends ServiceImpl<ProblemMapper, Problem> impl
case "HDU":
problemStrategy = new HDUProblemStrategy();
break;
case "CF":
problemStrategy = new CFProblemStrategy();
break;
default:
throw new Exception("未知的OJ的名字暂时不支持");
}
@ -394,7 +398,10 @@ public class ProblemServiceImpl extends ServiceImpl<ProblemMapper, Problem> impl
}
@Override
public boolean adminAddOtherOJProblem(Problem problem, String OJName) {
@Transactional
public boolean adminAddOtherOJProblem(ProblemStrategy.RemoteProblemInfo remoteProblemInfo, String OJName) {
Problem problem = remoteProblemInfo.getProblem();
boolean addProblemResult = problemMapper.insert(problem) == 1;
// 为新的其它oj题目添加对应的language
QueryWrapper<Language> languageQueryWrapper = new QueryWrapper<>();
@ -410,16 +417,32 @@ public class ProblemServiceImpl extends ServiceImpl<ProblemMapper, Problem> impl
// 为新的题目初始化problem_count表
boolean initProblemCountResult = problemCountService.save(new ProblemCount().setPid(problem.getId()));
QueryWrapper<Tag> tagQueryWrapper = new QueryWrapper<>();
tagQueryWrapper.eq("name", OJName);
Tag OJNameTag = tagService.getOne(tagQueryWrapper, false);
if (OJNameTag == null) {
OJNameTag = new Tag();
OJNameTag.setName(OJName);
tagService.saveOrUpdate(OJNameTag);
boolean addProblemTagResult = true;
List<Tag> addTagList = remoteProblemInfo.getTagList();
if (addTagList != null && addTagList.size() > 0) {
List<Tag> tagList = tagService.list();
// 已存在的tag不进行添加
for (Tag hasTag:tagList){
addTagList.removeIf(newTag -> newTag.getName().equals(hasTag.getName()));
}
tagService.saveOrUpdateBatch(addTagList);
List<ProblemTag> problemTagList = new LinkedList<>();
for (Tag tmp : remoteProblemInfo.getTagList()) {
problemTagList.add(new ProblemTag().setTid(tmp.getId()).setPid(problem.getId()));
}
addProblemTagResult = problemTagService.saveOrUpdateBatch(problemTagList);
} else {
QueryWrapper<Tag> tagQueryWrapper = new QueryWrapper<>();
tagQueryWrapper.eq("name", OJName);
Tag OJNameTag = tagService.getOne(tagQueryWrapper, false);
if (OJNameTag == null) {
OJNameTag = new Tag();
OJNameTag.setName(OJName);
tagService.saveOrUpdate(OJNameTag);
}
addProblemTagResult = problemTagService.saveOrUpdate(new ProblemTag().setTid(OJNameTag.getId())
.setPid(problem.getId()));
}
boolean addProblemTagResult = problemTagService.saveOrUpdate(new ProblemTag().setTid(OJNameTag.getId())
.setPid(problem.getId()));
return addProblemResult && addProblemTagResult && addProblemLanguageResult && initProblemCountResult;
}

View File

@ -36,8 +36,8 @@ public class JsoupUtils {
Connection connection = Jsoup.connect(url);
// 设置用户代理
connection.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36");
// 设置超时时间10
connection.timeout(10000);
// 设置超时时间15
connection.timeout(15000);
// 设置请求头
if (headers != null) {
connection.headers(headers);

View File

@ -23,6 +23,7 @@ import org.jsoup.nodes.Document;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import top.hcode.hoj.common.result.CommonResult;
import top.hcode.hoj.dao.*;
@ -34,6 +35,7 @@ import top.hcode.hoj.pojo.vo.UserRolesVo;
import top.hcode.hoj.service.UserInfoService;
import top.hcode.hoj.service.UserRoleService;
import top.hcode.hoj.service.impl.AnnouncementServiceImpl;
import top.hcode.hoj.service.impl.LanguageServiceImpl;
import top.hcode.hoj.service.impl.UserInfoServiceImpl;
import top.hcode.hoj.service.impl.UserRoleServiceImpl;
import top.hcode.hoj.utils.Constants;
@ -45,6 +47,7 @@ import java.io.IOException;
import java.net.*;
import java.text.MessageFormat;
import java.util.*;
import java.util.regex.Pattern;
/**
* @Author: Himit_ZH
@ -199,5 +202,106 @@ public class DataBackupApplicationTests {
System.out.println(info.getOutput());
}
@Test
public void Test7() throws IOException {
String JUDGE_NAME = "CF";
String HOST = "https://codeforces.com";
String PROBLEM_URL = "/problemset/problem/%s/%s";
String problemId = "1491F";
String contestId = ReUtil.get("([0-9]+)[A-Z]{1}[0-9]{0,1}", problemId, 1);
String problemNum = ReUtil.get("[0-9]+([A-Z]{1}[0-9]{0,1})", problemId, 1);
String url = HOST + String.format(PROBLEM_URL, contestId, problemNum);
Connection connection = JsoupUtils.getConnectionFromUrl(url, null, null);
Document document = JsoupUtils.getDocument(connection, null);
String html = document.html();
Problem info = new Problem();
info.setProblemId(JUDGE_NAME + "-" + problemId);
info.setTitle(ReUtil.get("<div class=\"title\">\\s*" + problemNum + "\\. ([\\s\\S]*?)</div>", html, 1).trim());
info.setTimeLimit(1000 * Integer.parseInt(ReUtil.get("</div>([\\d\\.]+) (seconds?|s)\\s*</div>", html, 1)));
info.setMemoryLimit(Integer.parseInt(ReUtil.get("</div>(\\d+) (megabytes|MB)\\s*</div>", html, 1)));
String tmpDesc = ReUtil.get("standard output\\s*</div></div><div>([\\s\\S]*?)</div><div class=\"input-specification",
html, 1);
if (StringUtils.isEmpty(tmpDesc)) {
tmpDesc = "<div>" + ReUtil.get("(<div class=\"input-file\">[\\s\\S]*?)</div><div class=\"input-specification", html, 1);
}
info.setDescription(tmpDesc.replaceAll("src=\"../../", "src=\"" + HOST + "/"));
info.setInput(ReUtil.get("<div class=\"section-title\">\\s*Input\\s*</div>([\\s\\S]*?)</div><div class=\"output-specification\">", html, 1));
info.setOutput(ReUtil.get("<div class=\"section-title\">\\s*Output\\s*</div>([\\s\\S]*?)</div><div class=\"sample-tests\">", html, 1));
StringBuilder sb = new StringBuilder("<input>");
sb.append(ReUtil.get("<div class=\"sample-test\"><div class=\"input\"><div class=\"title\">Input</div><pre>([\\s\\S]*?)</pre></div>", html, 1));
sb.append("</input><output>");
sb.append(ReUtil.get("<div class=\"output\"><div class=\"title\">Output</div><pre>([\\s\\S]*?)</pre></div></div>", html, 1)).append("</output>");
info.setExamples(sb.toString());
info.setHint(ReUtil.get("<div class=\"section-title\">\\s*Note\\s*</div>([\\s\\S]*?)</div></div>", html, 1));
info.setIsRemote(true);
info.setSource(String.format("<p>Problem<a style='color:#1A5CC8' href='https://codeforces.com/problemset/problem/%s/%s'>%s</a></p><p>" +
"Contest" + ReUtil.get("(<a[^<>]+/contest/\\d+\">.+?</a>)", html, 1).replace("/contest", HOST + "/contest")
.replace("color: black", "color: #009688;") + "</p>",
contestId, problemNum, JUDGE_NAME + "-" + problemId));
List<String> all = ReUtil.findAll(Pattern.compile("<span class=\"tag-box\" style=\"font-size:1\\.2rem;\" title=\"[\\s\\S]*?\">([\\s\\S]*?)</span>"), html, 1);
for (String tmp : all) {
System.out.println(tmp.trim());
}
}
@Autowired
private LanguageServiceImpl languageService;
@Test
public void Test8() throws IOException {
LinkedHashMap<String, String> languageList = new LinkedHashMap<>();
languageList.put("GNU GCC C11 5.1.0", "text/x-csrc");
languageList.put("Clang++17 Diagnostics", "text/x-c++src");
languageList.put("GNU G++11 5.1.0", "text/x-c++src");
languageList.put("GNU G++14 6.4.0", "text/x-c++src");
languageList.put("GNU G++17 7.3.0", "text/x-c++src");
languageList.put("Microsoft Visual C++ 2010", "text/x-c++src");
languageList.put("Microsoft Visual C++ 2017", "text/x-c++src");
languageList.put("C# Mono 5.18", "text/x-csharp");
languageList.put("D DMD32 v2.083.1", "text/x-d");
languageList.put("Go 1.11.4", "text/x-go");
languageList.put("Haskell GHC 8.6.3", "text/x-haskell");
languageList.put("Java 1.8.0_162", "text/x-java");
languageList.put("Kotlin 1.3.10", "text/x-java");
languageList.put("OCaml 4.02.1", "text/x-ocaml");
languageList.put("Delphi 7", "text/x-pascal");
languageList.put("Free Pascal 3.0.2", "text/x-pascal");
languageList.put("PascalABC.NET 3.4.2", "text/x-pascal");
languageList.put("Perl 5.20.1", "text/x-perl");
languageList.put("PHP 7.2.13", "text/x-php");
languageList.put("Python 2.7.15", "text/x-python");
languageList.put("Python 3.7.2", "text/x-python");
languageList.put("PyPy 2.7 (6.0.0)", "text/x-python");
languageList.put("PyPy 3.5 (6.0.0)", "text/x-python");
languageList.put("Ruby 2.0.0p645", "text/x-ruby");
languageList.put("Rust 1.31.1", "text/x-rustsrc");
languageList.put("Scala 2.12.8", "text/x-scala");
languageList.put("JavaScript V8 4.8.0", "text/javascript");
languageList.put("Node.js 9.4.0", "text/javascript");
List<Language> languageList1 = new LinkedList<>();
for (String key : languageList.keySet()) {
String tmp = languageList.get(key);
languageList1.add(new Language().setName(key).setDescription(key).setOj("CF").setIsSpj(false).setContentType(tmp));
}
boolean b = languageService.saveOrUpdateBatch(languageList1);
System.out.println(b);
}
}

View File

@ -80,8 +80,6 @@ export default {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
touch-action: none !important;
-ms-touch-action: none;
}
body {
background-color: #eee !important;
@ -282,4 +280,96 @@ a:hover {
.v-note-wrapper .v-note-panel {
height: 460px !important;
}
.tex-formula {
font-family: times new roman, sans-serif;
vertical-align: middle;
margin: 0;
border: medium none;
position: relative;
bottom: 2px;
}
.tex-span {
font-size: 125%;
font-family: times new roman, sans-serif;
white-space: nowrap;
}
.tex-font-size-tiny {
font-size: 70%;
}
.tex-font-size-script {
font-size: 75%;
}
.tex-font-size-footnotes {
font-size: 85%;
}
.tex-font-size-small {
font-size: 85%;
}
.tex-font-size-normal {
font-size: 100%;
}
.tex-font-size-large-1 {
font-size: 115%;
}
.tex-font-size-large-2 {
font-size: 130%;
}
.tex-font-size-large-3 {
font-size: 145%;
}
.tex-font-size-huge-1 {
font-size: 175%;
}
.tex-font-size-huge-2 {
font-size: 200%;
}
.tex-font-style-sf {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.tex-font-style-tt {
font-size: 110%;
font-family: courier new, monospace;
}
.tex-font-style-bf {
font-weight: bold;
}
.tex-font-style-it {
font-style: italic;
}
.tex-font-style-sl {
font-style: italic;
}
.tex-font-style-sc {
text-transform: uppercase;
}
.tex-font-style-striked {
text-decoration: line-through;
}
.tex-font-style-underline {
text-decoration: underline;
}
.tex-graphics {
display: block;
}
</style>

View File

@ -141,7 +141,10 @@ export const PROBLEM_LEVEL_RESERVE={
export const OJ_NAME = 'HOJ'
export const REMOTE_OJ = ['HDU']
export const REMOTE_OJ = [
{name:'HDU',key:"HDU"},
{name:"Codeforces",key:"CF"}
]
export const CONTEST_STATUS = {
'SCHEDULED': -1,

View File

@ -84,7 +84,16 @@ import 'codemirror/theme/material.css';
// mode
import 'codemirror/mode/clike/clike.js';
import 'codemirror/mode/python/python.js';
import 'codemirror/mode/pascal/pascal.js';
import 'codemirror/mode/pascal/pascal.js'; //pascal
import 'codemirror/mode/go/go.js'; //go
import 'codemirror/mode/d/d.js'; //d
import 'codemirror/mode/haskell/haskell.js'; //haskell
import 'codemirror/mode/mllike/mllike.js'; //OCaml
import 'codemirror/mode/perl/perl.js'; //perl
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
// active-line.js
import 'codemirror/addon/selection/active-line.js';

View File

@ -151,9 +151,9 @@
<el-form-item label="Remote OJ">
<el-select v-model="otherOJName" size="small">
<el-option
:label="name"
:value="name"
v-for="(name, index) in REMOTE_OJ"
:label="remoteOj.name"
:value="remoteOj.key"
v-for="(remoteOj, index) in REMOTE_OJ"
:key="index"
></el-option>
</el-select>
@ -204,7 +204,7 @@ export default {
addRemoteOJproblemLoading: false,
otherOJName: 'HDU',
otherOJProblemId: '',
REMOTE_OJ: [],
REMOTE_OJ: {},
};
},
mounted() {

View File

@ -8,7 +8,10 @@
<div slot="header" class="panel-title">
<span>{{ problemData.problem.title }}</span
><br />
<span
<span v-if="contestID && !contestEnded"
><el-tag effect="plain" size="small">比赛题目</el-tag></span
>
<span v-else-if="problemData.tags.length > 0"
><el-tag
v-for="tag in problemData.tags"
:key="tag"
@ -18,6 +21,9 @@
>{{ tag }}</el-tag
></span
>
<span v-else-if="problemData.tags.length == 0"
><el-tag effect="plain" size="small">暂无标签</el-tag></span
>
<div class="problem-menu">
<span>
<el-link
@ -129,7 +135,7 @@
</el-card>
</div>
<div v-if="problemData.problem.source">
<div v-if="problemData.problem.source && !contestID">
<p class="title">Source</p>
<p class="content" v-html="problemData.problem.source"></p>
</div>

View File

@ -98,7 +98,7 @@
min-width="100"
></vxe-table-column>
<vxe-table-column field="title" title="Title" min-width="250">
<vxe-table-column field="title" title="Title" min-width="180">
<template v-slot="{ row }">
<a :href="getProblemUri(row.problemId)" class="title-a">{{
row.title
@ -114,7 +114,7 @@
</template>
</vxe-table-column>
<vxe-table-column field="tag" title="Tag" min-width="200">
<vxe-table-column field="tag" title="Tag" min-width="250">
<template v-slot="{ row }">
<span
class="el-tag el-tag--medium el-tag--light is-hit"

File diff suppressed because one or more lines are too long

View File

@ -31,7 +31,7 @@ CREATE TABLE `announcement` (
PRIMARY KEY (`id`),
KEY `uid` (`uid`),
CONSTRAINT `announcement_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `user_info` (`uuid`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;
/*Table structure for table `auth` */
@ -97,7 +97,7 @@ CREATE TABLE `contest` (
PRIMARY KEY (`id`,`uid`),
KEY `uid` (`uid`),
CONSTRAINT `contest_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `user_info` (`uuid`) ON DELETE NO ACTION ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1009 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=1012 DEFAULT CHARSET=utf8;
/*Table structure for table `contest_announcement` */
@ -114,7 +114,7 @@ CREATE TABLE `contest_announcement` (
KEY `contest_announcement_ibfk_2` (`aid`),
CONSTRAINT `contest_announcement_ibfk_1` FOREIGN KEY (`cid`) REFERENCES `contest` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `contest_announcement_ibfk_2` FOREIGN KEY (`aid`) REFERENCES `announcement` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
/*Table structure for table `contest_explanation` */
@ -152,7 +152,7 @@ CREATE TABLE `contest_problem` (
KEY `contest_problem_ibfk_2` (`pid`),
CONSTRAINT `contest_problem_ibfk_1` FOREIGN KEY (`cid`) REFERENCES `contest` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `contest_problem_ibfk_2` FOREIGN KEY (`pid`) REFERENCES `problem` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;
/*Table structure for table `contest_record` */
@ -188,7 +188,7 @@ CREATE TABLE `contest_record` (
CONSTRAINT `contest_record_ibfk_3` FOREIGN KEY (`pid`) REFERENCES `problem` (`id`) ON DELETE NO ACTION ON UPDATE CASCADE,
CONSTRAINT `contest_record_ibfk_4` FOREIGN KEY (`cpid`) REFERENCES `contest_problem` (`id`) ON DELETE NO ACTION ON UPDATE CASCADE,
CONSTRAINT `contest_record_ibfk_5` FOREIGN KEY (`submit_id`) REFERENCES `judge` (`submit_id`) ON DELETE NO ACTION ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;
/*Table structure for table `contest_register` */
@ -206,7 +206,7 @@ CREATE TABLE `contest_register` (
KEY `contest_register_ibfk_2` (`uid`),
CONSTRAINT `contest_register_ibfk_1` FOREIGN KEY (`cid`) REFERENCES `contest` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `contest_register_ibfk_2` FOREIGN KEY (`uid`) REFERENCES `user_info` (`uuid`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
/*Table structure for table `contest_score` */
@ -252,6 +252,7 @@ DROP TABLE IF EXISTS `judge`;
CREATE TABLE `judge` (
`submit_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`pid` bigint(20) unsigned NOT NULL COMMENT '题目id',
`display_pid` varchar(255) NOT NULL COMMENT '题目展示id',
`uid` varchar(32) NOT NULL COMMENT '用户id',
`username` varchar(255) DEFAULT NULL COMMENT '用户名',
`submit_time` datetime NOT NULL COMMENT '提交的时间',
@ -271,14 +272,14 @@ CREATE TABLE `judge` (
`version` int(11) NOT NULL DEFAULT '0' COMMENT '乐观锁',
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP,
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`submit_id`,`pid`,`uid`,`cid`),
PRIMARY KEY (`submit_id`,`pid`,`display_pid`,`uid`,`cid`),
KEY `pid` (`pid`),
KEY `uid` (`uid`),
KEY `username` (`username`),
CONSTRAINT `judge_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `problem` (`id`) ON DELETE NO ACTION ON UPDATE CASCADE,
CONSTRAINT `judge_ibfk_2` FOREIGN KEY (`uid`) REFERENCES `user_info` (`uuid`) ON DELETE NO ACTION ON UPDATE CASCADE,
CONSTRAINT `judge_ibfk_3` FOREIGN KEY (`username`) REFERENCES `user_info` (`username`) ON DELETE NO ACTION ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=164 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=208 DEFAULT CHARSET=utf8;
/*Table structure for table `judge_case` */
@ -308,7 +309,7 @@ CREATE TABLE `judge_case` (
CONSTRAINT `judge_case_ibfk_2` FOREIGN KEY (`pid`) REFERENCES `problem` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `judge_case_ibfk_3` FOREIGN KEY (`submit_id`) REFERENCES `judge` (`submit_id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `judge_case_ibfk_4` FOREIGN KEY (`case_id`) REFERENCES `problem_case` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=201 DEFAULT CHARSET=utf8;
/*Table structure for table `language` */
@ -322,10 +323,11 @@ CREATE TABLE `language` (
`compile_command` mediumtext COMMENT '编译指令',
`template` longtext COMMENT '模板',
`is_spj` tinyint(1) DEFAULT '0' COMMENT '是否可作为特殊判题的一种语言',
`oj` varchar(255) DEFAULT NULL COMMENT '该语言属于哪个oj自身oj用ME',
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP,
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8;
/*Table structure for table `problem` */
@ -333,6 +335,7 @@ DROP TABLE IF EXISTS `problem`;
CREATE TABLE `problem` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`problem_id` varchar(255) NOT NULL COMMENT '问题的自定义ID 例如HOJ-1000',
`title` varchar(255) NOT NULL COMMENT '题目',
`author` varchar(255) DEFAULT '未知' COMMENT '作者',
`type` int(11) NOT NULL DEFAULT '0' COMMENT '0为ACM,1为OI',
@ -342,8 +345,8 @@ CREATE TABLE `problem` (
`input` longtext COMMENT '输入描述',
`output` longtext COMMENT '输出描述',
`examples` longtext COMMENT '题面样例',
`is_remote` tinyint(1) DEFAULT '0' COMMENT '是否为vj判题为真时source字段为oj名-题号',
`source` varchar(255) DEFAULT NULL COMMENT '题目来源vj判题时例如HDU-1000',
`is_remote` tinyint(1) DEFAULT '0' COMMENT '是否为vj判题',
`source` text COMMENT '题目来源',
`difficulty` int(11) DEFAULT '0' COMMENT '题目难度,0简单1中等2困难',
`hint` longtext COMMENT '备注,提醒',
`auth` int(11) DEFAULT '1' COMMENT '默认为1公开2为私有3为比赛题目',
@ -356,10 +359,10 @@ CREATE TABLE `problem` (
`case_version` varchar(40) DEFAULT '0' COMMENT '题目测试数据的版本号',
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP,
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
PRIMARY KEY (`id`,`problem_id`),
KEY `author` (`author`),
CONSTRAINT `problem_ibfk_1` FOREIGN KEY (`author`) REFERENCES `user_info` (`username`) ON DELETE NO ACTION ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1013 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=1034 DEFAULT CHARSET=utf8;
/*Table structure for table `problem_case` */
@ -377,7 +380,7 @@ CREATE TABLE `problem_case` (
PRIMARY KEY (`id`),
KEY `pid` (`pid`),
CONSTRAINT `problem_case_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `problem` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8;
/*Table structure for table `problem_count` */
@ -402,7 +405,7 @@ CREATE TABLE `problem_count` (
PRIMARY KEY (`id`,`pid`),
UNIQUE KEY `pid` (`pid`),
CONSTRAINT `problem_count_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `problem` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
/*Table structure for table `problem_language` */
@ -419,7 +422,7 @@ CREATE TABLE `problem_language` (
KEY `lid` (`lid`),
CONSTRAINT `problem_language_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `problem` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `problem_language_ibfk_2` FOREIGN KEY (`lid`) REFERENCES `language` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=46 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=305 DEFAULT CHARSET=utf8;
/*Table structure for table `problem_tag` */
@ -436,7 +439,7 @@ CREATE TABLE `problem_tag` (
KEY `tid` (`tid`),
CONSTRAINT `problem_tag_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `problem` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `problem_tag_ibfk_2` FOREIGN KEY (`tid`) REFERENCES `tag` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8;
/*Table structure for table `role` */
@ -483,7 +486,7 @@ CREATE TABLE `session` (
PRIMARY KEY (`id`),
KEY `uid` (`uid`),
CONSTRAINT `session_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `user_info` (`uuid`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=129 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=154 DEFAULT CHARSET=utf8;
/*Table structure for table `tag` */
@ -495,9 +498,9 @@ CREATE TABLE `tag` (
`color` varchar(10) DEFAULT NULL COMMENT '标签颜色',
`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP,
`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
PRIMARY KEY (`id`,`name`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;
/*Table structure for table `user_acproblem` */
@ -517,7 +520,7 @@ CREATE TABLE `user_acproblem` (
CONSTRAINT `user_acproblem_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `user_info` (`uuid`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `user_acproblem_ibfk_2` FOREIGN KEY (`pid`) REFERENCES `problem` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `user_acproblem_ibfk_3` FOREIGN KEY (`submit_id`) REFERENCES `judge` (`submit_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=83 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=96 DEFAULT CHARSET=utf8;
/*Table structure for table `user_info` */
@ -562,7 +565,7 @@ CREATE TABLE `user_record` (
PRIMARY KEY (`id`,`uid`),
KEY `uid` (`uid`),
CONSTRAINT `user_record_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `user_info` (`uuid`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=291 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=293 DEFAULT CHARSET=utf8;
/*Table structure for table `user_role` */
@ -579,7 +582,7 @@ CREATE TABLE `user_role` (
KEY `role_id` (`role_id`) USING BTREE,
CONSTRAINT `user_role_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `user_info` (`uuid`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `user_role_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=293 DEFAULT CHARSET=utf8;
) ENGINE=InnoDB AUTO_INCREMENT=295 DEFAULT CHARSET=utf8;
/* Trigger structure for table `contest` */