增加首页轮播图可设和ACM比赛封榜提交提示
This commit is contained in:
parent
fc274b035c
commit
735e3c6474
|
@ -31,6 +31,21 @@
|
|||
- "0.0.0.0:873:873"
|
||||
```
|
||||
|
||||
**同时,需要将MySQL的配置`MYSQL_PUBLIC_HOST`改成当前服务器的公网IP**
|
||||
|
||||
```shell
|
||||
vim .env # 修改与docker-compose.yml同目录下的配置文件
|
||||
```
|
||||
|
||||
```yaml
|
||||
# mysql的配置
|
||||
MYSQL_HOST=172.20.0.3
|
||||
# 请提供当前mysql所在服务器的公网ip
|
||||
MYSQL_PUBLIC_HOST=***
|
||||
MYSQL_PORT=3306
|
||||
MYSQL_ROOT_PASSWORD=hoj123456
|
||||
```
|
||||
|
||||
2. 在其它服务器(判题机服务器)中使用docker-compose运行judgeserver服务,具体操作如下:
|
||||
|
||||
**(注意:如果云服务器有防火墙请开启8088端口号,需要将判题服务暴露出去)**
|
||||
|
|
|
@ -60,6 +60,11 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-mail</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.retry</groupId>
|
||||
<artifactId>spring-retry</artifactId>
|
||||
</dependency>
|
||||
<!--分布式配置中心-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.springframework.boot.SpringApplication;
|
|||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.retry.annotation.EnableRetry;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
@ -13,6 +14,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
|
|||
* @Date: 2020/10/22 23:25
|
||||
* @Description:
|
||||
*/
|
||||
@EnableRetry
|
||||
@EnableScheduling // 开启定时任务
|
||||
@EnableDiscoveryClient // 开启注册发现
|
||||
@SpringBootApplication
|
||||
|
|
|
@ -30,6 +30,7 @@ public class CorsConfig implements WebMvcConfigurer {
|
|||
// /api/public/img/** /api/public/file/**
|
||||
registry.addResourceHandler(Constants.File.IMG_API.getPath() + "**",Constants.File.FILE_API.getPath() + "**")
|
||||
.addResourceLocations("file:" + Constants.File.USER_AVATAR_FOLDER.getPath() + File.separator,
|
||||
"file:" + Constants.File.MARKDOWN_FILE_FOLDER.getPath() + File.separator);
|
||||
"file:" + Constants.File.MARKDOWN_FILE_FOLDER.getPath() + File.separator,
|
||||
"file:" + Constants.File.HOME_CAROUSEL_FOLDER.getPath() + File.separator);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
package top.hcode.hoj.controller.admin;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.lang.Validator;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.text.UnicodeUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
|
@ -11,14 +13,18 @@ import org.springframework.cloud.client.ServiceInstance;
|
|||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.hcode.hoj.common.result.CommonResult;
|
||||
import top.hcode.hoj.pojo.entity.File;
|
||||
import top.hcode.hoj.pojo.vo.ConfigVo;
|
||||
import top.hcode.hoj.service.impl.ConfigServiceImpl;
|
||||
import top.hcode.hoj.service.impl.EmailServiceImpl;
|
||||
import top.hcode.hoj.service.impl.FileServiceImpl;
|
||||
import top.hcode.hoj.utils.Constants;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @Author: Himit_ZH
|
||||
|
@ -38,24 +44,27 @@ public class ConfigController {
|
|||
@Autowired
|
||||
private EmailServiceImpl emailService;
|
||||
|
||||
@Autowired
|
||||
private FileServiceImpl fileService;
|
||||
|
||||
/**
|
||||
* @MethodName getServiceInfo
|
||||
* @Params * @param null
|
||||
* @Params * @param null
|
||||
* @Description 获取当前服务的相关信息以及当前系统的cpu情况,内存使用情况
|
||||
* @Return CommonResult
|
||||
* @Since 2020/12/3
|
||||
*/
|
||||
|
||||
@RequiresRoles(value = {"root","admin","problem_admin"},logical = Logical.OR)
|
||||
@RequiresRoles(value = {"root", "admin", "problem_admin"}, logical = Logical.OR)
|
||||
@RequestMapping("/get-service-info")
|
||||
public CommonResult getServiceInfo(){
|
||||
public CommonResult getServiceInfo() {
|
||||
|
||||
return CommonResult.successResponse(configService.getServiceInfo());
|
||||
}
|
||||
|
||||
@RequiresRoles(value = {"root","admin","problem_admin"},logical = Logical.OR)
|
||||
@RequiresRoles(value = {"root", "admin", "problem_admin"}, logical = Logical.OR)
|
||||
@RequestMapping("/get-judge-service-info")
|
||||
public CommonResult getJudgeServiceInfo(){
|
||||
public CommonResult getJudgeServiceInfo() {
|
||||
return CommonResult.successResponse(configService.getJudgeServiceInfo());
|
||||
}
|
||||
|
||||
|
@ -76,14 +85,32 @@ public class ConfigController {
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
@RequiresPermissions("system_info_admin")
|
||||
@RequestMapping(value = "/set-web-config",method = RequestMethod.PUT)
|
||||
public CommonResult setWebConfig(@RequestBody HashMap<String,Object> params){
|
||||
@DeleteMapping("/home-carousel")
|
||||
public CommonResult deleteHomeCarousel(@RequestParam("id") Long id) {
|
||||
|
||||
File imgFile = fileService.getById(id);
|
||||
if (imgFile == null) {
|
||||
return CommonResult.errorResponse("文件id错误,图片不存在");
|
||||
}
|
||||
boolean isOk = fileService.removeById(id);
|
||||
if (isOk) {
|
||||
FileUtil.del(imgFile.getFilePath());
|
||||
return CommonResult.successResponse("删除成功!");
|
||||
} else {
|
||||
return CommonResult.errorResponse("删除失败!");
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresPermissions("system_info_admin")
|
||||
@RequestMapping(value = "/set-web-config", method = RequestMethod.PUT)
|
||||
public CommonResult setWebConfig(@RequestBody HashMap<String, Object> params) {
|
||||
|
||||
boolean result = configService.setWebConfig(params);
|
||||
if (result){
|
||||
return CommonResult.successResponse(null,"修改网站前端配置成功!");
|
||||
}else{
|
||||
if (result) {
|
||||
return CommonResult.successResponse(null, "修改网站前端配置成功!");
|
||||
} else {
|
||||
return CommonResult.errorResponse("修改失败!");
|
||||
}
|
||||
}
|
||||
|
@ -103,11 +130,11 @@ public class ConfigController {
|
|||
|
||||
@RequiresPermissions("system_info_admin")
|
||||
@PutMapping("/set-email-config")
|
||||
public CommonResult setEmailConfig(@RequestBody HashMap<String,Object> params) {
|
||||
public CommonResult setEmailConfig(@RequestBody HashMap<String, Object> params) {
|
||||
|
||||
boolean result = configService.setEmailConfig(params);
|
||||
if (result) {
|
||||
return CommonResult.successResponse(null,"修改邮箱配置成功!");
|
||||
return CommonResult.successResponse(null, "修改邮箱配置成功!");
|
||||
} else {
|
||||
return CommonResult.errorResponse("修改失败!");
|
||||
}
|
||||
|
@ -115,40 +142,40 @@ public class ConfigController {
|
|||
|
||||
@RequiresPermissions("system_info_admin")
|
||||
@PostMapping("/test-email")
|
||||
public CommonResult testEmail(@RequestBody HashMap<String,Object> params) throws MessagingException {
|
||||
public CommonResult testEmail(@RequestBody HashMap<String, Object> params) throws MessagingException {
|
||||
String email = (String) params.get("email");
|
||||
boolean isEmail = Validator.isEmail(email);
|
||||
if (isEmail){
|
||||
if (isEmail) {
|
||||
emailService.testEmail(email);
|
||||
return CommonResult.successResponse(null,"测试邮件已发送至指定邮箱!");
|
||||
}else{
|
||||
return CommonResult.successResponse(null, "测试邮件已发送至指定邮箱!");
|
||||
} else {
|
||||
return CommonResult.errorResponse("测试的邮箱不正确!");
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresPermissions("system_info_admin")
|
||||
@RequestMapping("/get-db-and-redis-config")
|
||||
public CommonResult getDBAndRedisConfig(){
|
||||
public CommonResult getDBAndRedisConfig() {
|
||||
|
||||
return CommonResult.successResponse(
|
||||
MapUtil.builder().put("dbName",configVo.getMysqlDBName())
|
||||
.put("dbHost", configVo.getMysqlHost())
|
||||
.put("dbPost", configVo.getMysqlPort())
|
||||
.put("dbUsername", configVo.getMysqlUsername())
|
||||
.put("dbPassword", configVo.getMysqlPassword())
|
||||
.put("redisHost", configVo.getRedisHost())
|
||||
.put("redisPort", configVo.getRedisPort())
|
||||
.put("redisPassword", configVo.getRedisPassword())
|
||||
.map()
|
||||
MapUtil.builder().put("dbName", configVo.getMysqlDBName())
|
||||
.put("dbHost", configVo.getMysqlHost())
|
||||
.put("dbPost", configVo.getMysqlPort())
|
||||
.put("dbUsername", configVo.getMysqlUsername())
|
||||
.put("dbPassword", configVo.getMysqlPassword())
|
||||
.put("redisHost", configVo.getRedisHost())
|
||||
.put("redisPort", configVo.getRedisPort())
|
||||
.put("redisPassword", configVo.getRedisPassword())
|
||||
.map()
|
||||
);
|
||||
}
|
||||
|
||||
@RequiresPermissions("system_info_admin")
|
||||
@PutMapping("/set-db-and-redis-config")
|
||||
public CommonResult setDBAndRedisConfig(@RequestBody HashMap<String,Object> params){
|
||||
public CommonResult setDBAndRedisConfig(@RequestBody HashMap<String, Object> params) {
|
||||
boolean result = configService.setDBAndRedisConfig(params);
|
||||
if (result) {
|
||||
return CommonResult.successResponse(null,"修改数据库配置成功!");
|
||||
return CommonResult.successResponse(null, "修改数据库配置成功!");
|
||||
} else {
|
||||
return CommonResult.errorResponse("修改失败!");
|
||||
}
|
||||
|
|
|
@ -189,6 +189,56 @@ public class FileController {
|
|||
}
|
||||
|
||||
|
||||
|
||||
@RequestMapping(value = "/upload-carouse-img", method = RequestMethod.POST)
|
||||
@RequiresAuthentication
|
||||
@ResponseBody
|
||||
@Transactional
|
||||
@RequiresRoles("root")
|
||||
public CommonResult uploadCarouselImg(@RequestParam("file") MultipartFile image, HttpServletRequest request) {
|
||||
|
||||
if (image == null) {
|
||||
return CommonResult.errorResponse("上传的图片文件不能为空!");
|
||||
}
|
||||
|
||||
//获取文件后缀
|
||||
String suffix = image.getOriginalFilename().substring(image.getOriginalFilename().lastIndexOf(".") + 1);
|
||||
if (!"jpg,jpeg,gif,png,webp,jfif,svg".toUpperCase().contains(suffix.toUpperCase())) {
|
||||
return CommonResult.errorResponse("请选择jpg,jpeg,gif,png,webp,jfif,svg格式的头像图片!");
|
||||
}
|
||||
//若不存在该目录,则创建目录
|
||||
FileUtil.mkdir(Constants.File.HOME_CAROUSEL_FOLDER.getPath());
|
||||
//通过UUID生成唯一文件名
|
||||
String filename = IdUtil.simpleUUID() + "." + suffix;
|
||||
try {
|
||||
//将文件保存指定目录
|
||||
image.transferTo(FileUtil.file(Constants.File.HOME_CAROUSEL_FOLDER.getPath() + File.separator + filename));
|
||||
} catch (Exception e) {
|
||||
log.error("图片文件上传异常-------------->{}", e.getMessage());
|
||||
return CommonResult.errorResponse("服务器异常:图片上传失败!", CommonResult.STATUS_ERROR);
|
||||
}
|
||||
|
||||
// 获取当前登录用户
|
||||
HttpSession session = request.getSession();
|
||||
UserRolesVo userRolesVo = (UserRolesVo) session.getAttribute("userInfo");
|
||||
|
||||
|
||||
// 插入file表记录
|
||||
top.hcode.hoj.pojo.entity.File imgFile = new top.hcode.hoj.pojo.entity.File();
|
||||
imgFile.setName(filename).setFolderPath(Constants.File.HOME_CAROUSEL_FOLDER.getPath())
|
||||
.setFilePath(Constants.File.HOME_CAROUSEL_FOLDER.getPath() + File.separator + filename)
|
||||
.setSuffix(suffix)
|
||||
.setType("carousel")
|
||||
.setUid(userRolesVo.getUid());
|
||||
fileService.saveOrUpdate(imgFile);
|
||||
|
||||
return CommonResult.successResponse(MapUtil.builder()
|
||||
.put("id", imgFile.getId())
|
||||
.put("url", Constants.File.IMG_API.getPath() + filename)
|
||||
.map(), "上传图片成功!");
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/upload-testcase-zip")
|
||||
@ResponseBody
|
||||
@RequiresRoles(value = {"root", "admin", "problem_admin"}, logical = Logical.OR)
|
||||
|
@ -387,12 +437,10 @@ public class FileController {
|
|||
|
||||
QueryWrapper<ContestRecord> wrapper = new QueryWrapper<ContestRecord>().eq("cid", cid)
|
||||
.isNotNull("status")
|
||||
// 如果已经开启了封榜模式
|
||||
.notBetween(isOpenSealRank, "submit_time", contest.getSealRankTime(), contest.getEndTime())
|
||||
.orderByAsc("time");
|
||||
List<ContestRecord> contestRecordList = contestRecordService.list(wrapper);
|
||||
Assert.notEmpty(contestRecordList, "比赛暂无排行榜记录!");
|
||||
List<ACMContestRankVo> acmContestRankVoList = contestRecordService.calcACMRank(contestRecordList);
|
||||
List<ACMContestRankVo> acmContestRankVoList = contestRecordService.calcACMRank(isOpenSealRank,contest,contestRecordList);
|
||||
EasyExcel.write(response.getOutputStream())
|
||||
.head(fileService.getContestRankExcelHead(contestProblemDisplayIDList, true))
|
||||
.sheet("rank")
|
||||
|
|
|
@ -589,6 +589,7 @@ public class AccountController {
|
|||
.setNickname(nickname)
|
||||
.setSignature((String) params.get("signature"))
|
||||
.setBlog((String) params.get("blog"))
|
||||
.setEmail(userRolesVo.getEmail())
|
||||
.setGithub((String) params.get("github"))
|
||||
.setSchool((String) params.get("school"))
|
||||
.setNumber((String) params.get("number"));
|
||||
|
|
|
@ -451,7 +451,7 @@ public class ContestController {
|
|||
return commonResult;
|
||||
}
|
||||
|
||||
// 校验该比赛是否开启了封榜模式
|
||||
// 校验该比赛是否开启了封榜模式,超级管理员和比赛创建者可以直接看到实际榜单
|
||||
boolean isOpenSealRank = contestService.isSealRank(userRolesVo.getUid(), contest, forceRefresh, isRoot);
|
||||
|
||||
|
||||
|
@ -460,16 +460,13 @@ public class ContestController {
|
|||
|
||||
QueryWrapper<ContestRecord> wrapper = new QueryWrapper<ContestRecord>().eq("cid", cid)
|
||||
.isNotNull("status")
|
||||
// 如果已经开启了封榜模式
|
||||
.between(isOpenSealRank, "submit_time", contest.getStartTime(), contest.getSealRankTime())
|
||||
.between(!isOpenSealRank, "submit_time", contest.getStartTime(), contest.getEndTime())
|
||||
.ne("username", contest.getAuthor())
|
||||
.orderByAsc("time");
|
||||
|
||||
List<ContestRecord> contestRecordList = contestRecordService.list(wrapper);
|
||||
|
||||
// 进行排行榜计算以及排名分页
|
||||
resultList = contestRecordService.getContestACMRank(contestRecordList, currentPage, limit);
|
||||
resultList = contestRecordService.getContestACMRank(isOpenSealRank,contest, contestRecordList, currentPage, limit);
|
||||
|
||||
} else { //OI比赛:以最后一次提交得分作为该题得分
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package top.hcode.hoj.controller.oj;
|
|||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.text.UnicodeUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
@ -10,11 +11,13 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.hcode.hoj.common.result.CommonResult;
|
||||
import top.hcode.hoj.dao.ContestMapper;
|
||||
import top.hcode.hoj.pojo.entity.File;
|
||||
import top.hcode.hoj.pojo.vo.ACMRankVo;
|
||||
import top.hcode.hoj.pojo.vo.AnnouncementVo;
|
||||
import top.hcode.hoj.pojo.vo.ConfigVo;
|
||||
import top.hcode.hoj.pojo.vo.ContestVo;
|
||||
import top.hcode.hoj.service.impl.AnnouncementServiceImpl;
|
||||
import top.hcode.hoj.service.impl.FileServiceImpl;
|
||||
import top.hcode.hoj.service.impl.UserRecordServiceImpl;
|
||||
import top.hcode.hoj.utils.Constants;
|
||||
import top.hcode.hoj.utils.RedisUtils;
|
||||
|
@ -23,6 +26,7 @@ import java.util.ArrayList;
|
|||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @Author: Himit_ZH
|
||||
|
@ -49,6 +53,9 @@ public class HomeController {
|
|||
@Autowired
|
||||
private RedisUtils redisUtils;
|
||||
|
||||
@Autowired
|
||||
private FileServiceImpl fileService;
|
||||
|
||||
/**
|
||||
* @MethodName getRecentContest
|
||||
* @Params * @param null
|
||||
|
@ -65,6 +72,27 @@ public class HomeController {
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* @MethodName getHomeCarousel
|
||||
* @Params
|
||||
* @Description 获取主页轮播图
|
||||
* @Return
|
||||
* @Since 2021/9/4
|
||||
*/
|
||||
@GetMapping("/home-carousel")
|
||||
public CommonResult getHomeCarousel() {
|
||||
List<File> fileList = fileService.queryCarouselFileList();
|
||||
List<HashMap<String, Object>> apiList = fileList.stream().map(f -> {
|
||||
HashMap<String, Object> param = new HashMap<>(2);
|
||||
param.put("id", f.getId());
|
||||
param.put("url", Constants.File.IMG_API.getPath() + f.getName());
|
||||
return param;
|
||||
}).collect(Collectors.toList());
|
||||
return CommonResult.successResponse(apiList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @MethodName getRecentSevenACRank
|
||||
* @Params * @param null
|
||||
|
@ -118,7 +146,6 @@ public class HomeController {
|
|||
return CommonResult.successResponse(announcementList);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @MethodName getWebConfig
|
||||
* @Params * @param null
|
||||
|
|
|
@ -21,4 +21,8 @@ public interface FileMapper extends BaseMapper<File> {
|
|||
List<File> queryDeleteAvatarList();
|
||||
|
||||
|
||||
@Select("select * from file where (type = 'carousel')")
|
||||
List<File> queryCarouselFileList();
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
(SELECT COUNT( DISTINCT pid ) FROM user_acproblem WHERE uid =u.uuid
|
||||
and DATE(gmt_create) >= DATE_SUB(CURDATE(),INTERVAL 7 DAY)) AS ac,
|
||||
(SELECT COUNT(uid) FROM judge WHERE uid=u.uuid AND cid=0
|
||||
and DATE(submit_time) >= DATE_SUB(CURDATE(),INTERVAL 7 DAY)) AS total
|
||||
and DATE(gmt_modified) >= DATE_SUB(CURDATE(),INTERVAL 7 DAY)) AS total
|
||||
FROM user_info u WHERE u.status = 0
|
||||
ORDER BY ac DESC,total ASC LIMIT 10
|
||||
</select>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package top.hcode.hoj.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import top.hcode.hoj.pojo.entity.Contest;
|
||||
import top.hcode.hoj.pojo.entity.UserInfo;
|
||||
import top.hcode.hoj.pojo.vo.ACMContestRankVo;
|
||||
import top.hcode.hoj.pojo.entity.ContestRecord;
|
||||
|
@ -22,7 +23,7 @@ public interface ContestRecordService extends IService<ContestRecord> {
|
|||
|
||||
IPage<ContestRecord> getACInfo(Integer currentPage, Integer limit, Integer status, Long cid, String contestCreatorId);
|
||||
|
||||
IPage<ACMContestRankVo> getContestACMRank(List<ContestRecord> contestRecordList, int currentPage, int limit);
|
||||
IPage<ACMContestRankVo> getContestACMRank(Boolean isOpenSealRank, Contest contest, List<ContestRecord> contestRecordList, int currentPage, int limit);
|
||||
|
||||
IPage<OIContestRankVo> getContestOIRank(Long cid, String contestAuthor, Boolean isOpenSealRank, Date sealTime, Date startTime, Date endTime, int currentPage, int limit);
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ public interface FileService extends IService<File> {
|
|||
|
||||
List<File> queryDeleteAvatarList();
|
||||
|
||||
List<File> queryCarouselFileList();
|
||||
|
||||
List<List<String>> getContestRankExcelHead(List<String> contestProblemDisplayIDList, Boolean isACM);
|
||||
|
||||
List<List<Object>> changeACMContestRankToExcelRowList(List<ACMContestRankVo> acmContestRankVoList, List<String> contestProblemDisplayIDList);
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package top.hcode.hoj.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import top.hcode.hoj.dao.UserInfoMapper;
|
||||
import top.hcode.hoj.pojo.entity.Contest;
|
||||
import top.hcode.hoj.pojo.entity.UserInfo;
|
||||
import top.hcode.hoj.pojo.vo.ACMContestRankVo;
|
||||
import top.hcode.hoj.pojo.entity.ContestRecord;
|
||||
|
@ -105,10 +107,12 @@ public class ContestRecordServiceImpl extends ServiceImpl<ContestRecordMapper, C
|
|||
|
||||
|
||||
@Override
|
||||
public IPage<ACMContestRankVo> getContestACMRank(List<ContestRecord> contestRecordList, int currentPage, int limit) {
|
||||
public IPage<ACMContestRankVo> getContestACMRank(Boolean isOpenSealRank, Contest contest,
|
||||
List<ContestRecord> contestRecordList,
|
||||
int currentPage, int limit) {
|
||||
|
||||
// 进行排序计算
|
||||
List<ACMContestRankVo> orderResultList = calcACMRank(contestRecordList);
|
||||
List<ACMContestRankVo> orderResultList = calcACMRank(isOpenSealRank, contest, contestRecordList);
|
||||
// 计算好排行榜,然后进行分页
|
||||
Page<ACMContestRankVo> page = new Page<>(currentPage, limit);
|
||||
int count = orderResultList.size();
|
||||
|
@ -159,7 +163,7 @@ public class ContestRecordServiceImpl extends ServiceImpl<ContestRecordMapper, C
|
|||
}
|
||||
|
||||
|
||||
public List<ACMContestRankVo> calcACMRank(List<ContestRecord> contestRecordList) {
|
||||
public List<ACMContestRankVo> calcACMRank(boolean isOpenSealRank, Contest contest, List<ContestRecord> contestRecordList) {
|
||||
|
||||
List<UserInfo> superAdminList = getSuperAdminList();
|
||||
|
||||
|
@ -203,46 +207,60 @@ public class ContestRecordServiceImpl extends ServiceImpl<ContestRecordMapper, C
|
|||
|
||||
HashMap<String, Object> problemSubmissionInfo = ACMContestRankVo.getSubmissionInfo().getOrDefault(contestRecord.getDisplayId(), new HashMap<>());
|
||||
|
||||
// 如果该题目已经AC过了,那么只记录提交次数,其它都不记录了
|
||||
ACMContestRankVo.setTotal(ACMContestRankVo.getTotal() + 1);
|
||||
if ((Boolean) problemSubmissionInfo.getOrDefault("isAC", false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 记录已经按题目提交耗时time升序了
|
||||
// 如果是当前是开启封榜的时段和同时该提交是处于封榜时段 尝试次数+1
|
||||
if (isOpenSealRank && isInSealTimeSubmission(contest, contestRecord.getSubmitTime())) {
|
||||
|
||||
// 通过的话
|
||||
if (contestRecord.getStatus().intValue() == Constants.Contest.RECORD_AC.getCode()) {
|
||||
// 总解决题目次数ac+1
|
||||
ACMContestRankVo.setAc(ACMContestRankVo.getAc() + 1);
|
||||
int tryNum = (int) problemSubmissionInfo.getOrDefault("tryNum", 0);
|
||||
problemSubmissionInfo.put("tryNum", tryNum + 1);
|
||||
|
||||
// 判断是不是first AC
|
||||
boolean isFirstAC = false;
|
||||
Long time = firstACMap.getOrDefault(contestRecord.getDisplayId(), null);
|
||||
if (time == null) {
|
||||
isFirstAC = true;
|
||||
firstACMap.put(contestRecord.getDisplayId(), contestRecord.getTime());
|
||||
} else {
|
||||
// 相同提交时间也是first AC
|
||||
if (time.longValue() == contestRecord.getTime().longValue()) {
|
||||
isFirstAC = true;
|
||||
}
|
||||
} else {
|
||||
|
||||
// 如果该题目已经AC过了,其它都不记录了
|
||||
if ((Boolean) problemSubmissionInfo.getOrDefault("isAC", false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int errorNumber = (int) problemSubmissionInfo.getOrDefault("errorNum", 0);
|
||||
problemSubmissionInfo.put("isAC", true);
|
||||
problemSubmissionInfo.put("isFirstAC", isFirstAC);
|
||||
problemSubmissionInfo.put("ACTime", contestRecord.getTime());
|
||||
problemSubmissionInfo.put("errorNum", errorNumber);
|
||||
// 记录已经按题目提交耗时time升序了
|
||||
|
||||
// 同时计算总耗时,总耗时加上 该题目未AC前的错误次数*20*60+题目AC耗时
|
||||
ACMContestRankVo.setTotalTime(ACMContestRankVo.getTotalTime() + errorNumber * 20 * 60 + contestRecord.getTime());
|
||||
// 通过的话
|
||||
if (contestRecord.getStatus().intValue() == Constants.Contest.RECORD_AC.getCode()) {
|
||||
// 总解决题目次数ac+1
|
||||
ACMContestRankVo.setAc(ACMContestRankVo.getAc() + 1);
|
||||
|
||||
// 未通过同时需要记录罚时次数
|
||||
} else if (contestRecord.getStatus().intValue() == Constants.Contest.RECORD_NOT_AC_PENALTY.getCode()) {
|
||||
// 判断是不是first AC
|
||||
boolean isFirstAC = false;
|
||||
Long time = firstACMap.getOrDefault(contestRecord.getDisplayId(), null);
|
||||
if (time == null) {
|
||||
isFirstAC = true;
|
||||
firstACMap.put(contestRecord.getDisplayId(), contestRecord.getTime());
|
||||
} else {
|
||||
// 相同提交时间也是first AC
|
||||
if (time.longValue() == contestRecord.getTime().longValue()) {
|
||||
isFirstAC = true;
|
||||
}
|
||||
}
|
||||
|
||||
int errorNumber = (int) problemSubmissionInfo.getOrDefault("errorNum", 0);
|
||||
problemSubmissionInfo.put("errorNum", errorNumber + 1);
|
||||
int errorNumber = (int) problemSubmissionInfo.getOrDefault("errorNum", 0);
|
||||
problemSubmissionInfo.put("isAC", true);
|
||||
problemSubmissionInfo.put("isFirstAC", isFirstAC);
|
||||
problemSubmissionInfo.put("ACTime", contestRecord.getTime());
|
||||
problemSubmissionInfo.put("errorNum", errorNumber);
|
||||
|
||||
// 同时计算总耗时,总耗时加上 该题目未AC前的错误次数*20*60+题目AC耗时
|
||||
ACMContestRankVo.setTotalTime(ACMContestRankVo.getTotalTime() + errorNumber * 20 * 60 + contestRecord.getTime());
|
||||
|
||||
// 未通过同时需要记录罚时次数
|
||||
} else if (contestRecord.getStatus().intValue() == Constants.Contest.RECORD_NOT_AC_PENALTY.getCode()) {
|
||||
|
||||
int errorNumber = (int) problemSubmissionInfo.getOrDefault("errorNum", 0);
|
||||
problemSubmissionInfo.put("errorNum", errorNumber + 1);
|
||||
}else{
|
||||
|
||||
int errorNumber = (int) problemSubmissionInfo.getOrDefault("errorNum", 0);
|
||||
problemSubmissionInfo.put("errorNum", errorNumber);
|
||||
}
|
||||
}
|
||||
ACMContestRankVo.getSubmissionInfo().put(contestRecord.getDisplayId(), problemSubmissionInfo);
|
||||
}
|
||||
|
@ -341,4 +359,9 @@ public class ContestRecordServiceImpl extends ServiceImpl<ContestRecordMapper, C
|
|||
.collect(Collectors.toList());
|
||||
return orderResultList;
|
||||
}
|
||||
|
||||
|
||||
private boolean isInSealTimeSubmission(Contest contest, Date submissionDate) {
|
||||
return DateUtil.isIn(submissionDate, contest.getSealRankTime(), contest.getEndTime());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,7 +169,15 @@ public class EmailServiceImpl implements EmailService {
|
|||
context.setVariable(Constants.Email.OJ_SHORT_NAME.name(), ojShortName.toUpperCase());
|
||||
context.setVariable(Constants.Email.OJ_URL.name(), ojAddr);
|
||||
context.setVariable(Constants.Email.EMAIL_BACKGROUND_IMG.name(), ojEmailBg);
|
||||
context.setVariable("RESET_URL", Constants.Email.OJ_URL.getValue() + "/reset-password?username=" + username + "&code=" + code);
|
||||
|
||||
String resetUrl;
|
||||
if (ojAddr.endsWith("/")) {
|
||||
resetUrl = ojAddr + "reset-password?username=" + username + "&code=" + code;
|
||||
} else {
|
||||
resetUrl = ojAddr + "/reset-password?username=" + username + "&code=" + code;
|
||||
}
|
||||
|
||||
context.setVariable("RESET_URL", resetUrl);
|
||||
context.setVariable("EXPIRE_TIME", expireTime.toString());
|
||||
context.setVariable("USERNAME", username);
|
||||
|
||||
|
|
|
@ -33,6 +33,11 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements Fi
|
|||
return fileMapper.queryDeleteAvatarList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<File> queryCarouselFileList(){
|
||||
return fileMapper.queryCarouselFileList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<List<String>> getContestRankExcelHead(List<String> contestProblemDisplayIDList, Boolean isACM) {
|
||||
List<List<String>> headList = new LinkedList<>();
|
||||
|
|
|
@ -10,6 +10,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
@ -23,6 +25,7 @@ import top.hcode.hoj.utils.Constants;
|
|||
import top.hcode.hoj.utils.JsoupUtils;
|
||||
import top.hcode.hoj.utils.RedisUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -51,7 +54,6 @@ import java.util.concurrent.TimeUnit;
|
|||
* "C" 代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。
|
||||
*/
|
||||
@Service
|
||||
@Async
|
||||
@Slf4j(topic = "hoj")
|
||||
public class ScheduleServiceImpl implements ScheduleService {
|
||||
|
||||
|
@ -203,14 +205,8 @@ public class ScheduleServiceImpl implements ScheduleService {
|
|||
// 格式化api
|
||||
String ratingAPI = String.format(codeforcesUserInfoAPI, cfUsername);
|
||||
try {
|
||||
// 防止cf的频率限制
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(10);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// 连接api,获取json格式对象
|
||||
JSONObject resultObject = JsoupUtils.getJsonFromConnection(JsoupUtils.getConnectionFromUrl(ratingAPI, null, null));
|
||||
JSONObject resultObject = getCFUserInfo(ratingAPI);
|
||||
// 获取状态码
|
||||
String status = resultObject.getStr("status");
|
||||
// 如果查无此用户,则跳过
|
||||
|
@ -236,4 +232,11 @@ public class ScheduleServiceImpl implements ScheduleService {
|
|||
log.info("获取Codeforces Rating成功!");
|
||||
}
|
||||
|
||||
@Retryable(value = Exception.class,
|
||||
maxAttempts = 5,
|
||||
backoff = @Backoff(delay = 500))
|
||||
public JSONObject getCFUserInfo(String url) throws Exception {
|
||||
return JsoupUtils.getJsonFromConnection(JsoupUtils.getConnectionFromUrl(url, null, null));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -153,6 +153,8 @@ public class Constants {
|
|||
|
||||
USER_AVATAR_FOLDER("/hoj/file/avatar"),
|
||||
|
||||
HOME_CAROUSEL_FOLDER("/hoj/file/carousel"),
|
||||
|
||||
MARKDOWN_FILE_FOLDER("/hoj/file/md"),
|
||||
|
||||
IMG_API("/api/public/img/"),
|
||||
|
|
|
@ -163,7 +163,7 @@ public class HduJudge implements RemoteJudgeStrategy {
|
|||
// TODO 添加结果对应的状态
|
||||
private static final Map<String, Constants.Judge> statusTypeMap = new HashMap<String, Constants.Judge>() {
|
||||
{
|
||||
put("Submitted", Constants.Judge.STATUS_SUBMITTING);
|
||||
put("Submitted", Constants.Judge.STATUS_PENDING);
|
||||
put("Accepted", Constants.Judge.STATUS_ACCEPTED);
|
||||
put("Wrong Answer", Constants.Judge.STATUS_WRONG_ANSWER);
|
||||
put("Compilation Error", Constants.Judge.STATUS_COMPILE_ERROR);
|
||||
|
@ -171,6 +171,7 @@ public class HduJudge implements RemoteJudgeStrategy {
|
|||
put("Running", Constants.Judge.STATUS_JUDGING);
|
||||
put("Compiling", Constants.Judge.STATUS_COMPILING);
|
||||
put("Time Limit Exceeded", Constants.Judge.STATUS_TIME_LIMIT_EXCEEDED);
|
||||
put("Memory Limit Exceeded", Constants.Judge.STATUS_MEMORY_LIMIT_EXCEEDED);
|
||||
put("Presentation Error", Constants.Judge.STATUS_PRESENTATION_ERROR);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package top.hcode.hoj.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
@ -21,6 +18,7 @@ import java.util.Date;
|
|||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@ApiModel(value="File对象", description="")
|
||||
@TableName("`file`")
|
||||
public class File {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
@ -31,6 +29,7 @@ public class File {
|
|||
private String uid;
|
||||
|
||||
@ApiModelProperty(value = "文件所属类型,例如avatar")
|
||||
@TableField("`type`")
|
||||
private String type;
|
||||
|
||||
@ApiModelProperty(value = "文件名")
|
||||
|
@ -46,6 +45,7 @@ public class File {
|
|||
private String filePath;
|
||||
|
||||
@ApiModelProperty(value = "是否删除")
|
||||
@TableField("`delete`")
|
||||
private Boolean delete;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
|
|
|
@ -254,6 +254,10 @@ a:hover {
|
|||
background-color: #a9f5af;
|
||||
color: #3c763d;
|
||||
}
|
||||
.try {
|
||||
background-color: #ff9800;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.oi-0,
|
||||
.wa {
|
||||
|
|
|
@ -118,6 +118,10 @@ const ojApi = {
|
|||
return ajax('/api/get-website-config', 'get', {
|
||||
})
|
||||
},
|
||||
getHomeCarousel(){
|
||||
return ajax('/api/home-carousel', 'get', {
|
||||
})
|
||||
},
|
||||
getRecentContests(){
|
||||
return ajax('/api/get-recent-contest', 'get', {
|
||||
})
|
||||
|
@ -654,6 +658,7 @@ const adminApi = {
|
|||
data
|
||||
})
|
||||
},
|
||||
|
||||
// 系统配置
|
||||
admin_getSMTPConfig () {
|
||||
return ajax('/api/admin/config/get-email-config', 'get')
|
||||
|
@ -663,6 +668,15 @@ const adminApi = {
|
|||
data
|
||||
})
|
||||
},
|
||||
|
||||
admin_deleteHomeCarousel(id){
|
||||
return ajax('/api/admin/config/home-carousel', 'delete', {
|
||||
params:{
|
||||
id
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
admin_testSMTPConfig (email) {
|
||||
return ajax('/api/admin/config/test-email', 'post', {
|
||||
data: {
|
||||
|
|
|
@ -111,7 +111,7 @@ export default {
|
|||
},
|
||||
countDown() {
|
||||
let i = this.time;
|
||||
this.resetText = i + 's, ' + this.$i18n.t('m.Watting_Can_Resend_Email');
|
||||
this.resetText = i + 's, ' + this.$i18n.t('m.Waiting_Can_Resend_Email');
|
||||
if (i == 0) {
|
||||
this.btnResetPwdDisabled = false;
|
||||
this.resetText = this.$i18n.t('m.Send_Password_Reset_Email');
|
||||
|
|
|
@ -114,6 +114,7 @@ export const m = {
|
|||
Project_Url:'Project Url',
|
||||
Web_Desc: 'Web Desc',
|
||||
Allow_Register: 'Allow Register',
|
||||
Home_Rotation_Chart:'Home Rotation Chart',
|
||||
SMTP_Config: 'SMTP Config',
|
||||
Email_BG:'BG IMG',
|
||||
Email_BG_Desc:'SMTP Template Background IMG Address',
|
||||
|
|
|
@ -114,6 +114,7 @@ export const m = {
|
|||
Project_Url:'项目地址',
|
||||
Web_Desc: '网站简介',
|
||||
Allow_Register: '是否允许注册',
|
||||
Home_Rotation_Chart:'首页轮播图',
|
||||
SMTP_Config: 'SMTP 设置',
|
||||
Email_BG:'邮件背景',
|
||||
Email_BG_Desc:'请输入邮件背景图的URL链接',
|
||||
|
|
|
@ -100,6 +100,70 @@
|
|||
>
|
||||
</el-card>
|
||||
|
||||
<el-card style="margin-top:15px">
|
||||
<div slot="header">
|
||||
<span class="panel-title home-title">{{
|
||||
$t('m.Home_Rotation_Chart')
|
||||
}}</span>
|
||||
</div>
|
||||
|
||||
<ul class="el-upload-list el-upload-list--picture-card">
|
||||
<li
|
||||
tabindex="0"
|
||||
class="el-upload-list__item is-ready"
|
||||
v-for="(img, index) in carouselImgList"
|
||||
:key="index"
|
||||
>
|
||||
<div>
|
||||
<img
|
||||
:src="img.url"
|
||||
alt="load faild"
|
||||
style="height:146px;width:146x"
|
||||
class="el-upload-list__item-thumbnail"
|
||||
/><span class="el-upload-list__item-actions">
|
||||
<span
|
||||
class="el-upload-list__item-preview"
|
||||
@click="handlePictureCardPreview(img)"
|
||||
>
|
||||
<i class="el-icon-zoom-in"></i>
|
||||
</span>
|
||||
<span
|
||||
v-if="!disabled"
|
||||
class="el-upload-list__item-delete"
|
||||
@click="handleDownload(img)"
|
||||
>
|
||||
<i class="el-icon-download"></i>
|
||||
</span>
|
||||
<span
|
||||
v-if="!disabled"
|
||||
class="el-upload-list__item-delete"
|
||||
@click="handleRemove(img, index)"
|
||||
>
|
||||
<i class="el-icon-delete"></i>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<el-upload
|
||||
action="/api/file/upload-carouse-img"
|
||||
list-type="picture-card"
|
||||
accept="image/gif,image/jpeg,image/jpg,image/png,image/svg,image/jfif,image/webp"
|
||||
:on-preview="handlePictureCardPreview"
|
||||
:on-remove="handleRemove"
|
||||
style="display: inline;"
|
||||
>
|
||||
<i class="el-icon-plus"></i>
|
||||
</el-upload>
|
||||
<el-dialog :visible.sync="dialogVisible">
|
||||
<img width="100%" :src="dialogImageUrl" alt="" />
|
||||
</el-dialog>
|
||||
<el-dialog :visible.sync="dialogVisible">
|
||||
<img width="100%" :src="dialogImageUrl" alt="" />
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
|
||||
<el-card style="margin-top:15px">
|
||||
<div slot="header">
|
||||
<span class="panel-title home-title">{{ $t('m.SMTP_Config') }}</span>
|
||||
|
@ -279,6 +343,7 @@
|
|||
<script>
|
||||
import api from '@/common/api';
|
||||
import myMessage from '@/common/message';
|
||||
import utils from '@/common/utils';
|
||||
export default {
|
||||
name: 'SystemConfig',
|
||||
data() {
|
||||
|
@ -296,6 +361,10 @@ export default {
|
|||
},
|
||||
websiteConfig: {},
|
||||
databaseConfig: {},
|
||||
dialogImageUrl: '',
|
||||
dialogVisible: false,
|
||||
disabled: false,
|
||||
carouselImgList: [],
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
|
@ -307,6 +376,11 @@ export default {
|
|||
myMessage.warning('No STMP Config');
|
||||
}
|
||||
});
|
||||
|
||||
api.getHomeCarousel().then((res) => {
|
||||
this.carouselImgList = res.data.data;
|
||||
});
|
||||
|
||||
api
|
||||
.admin_getWebsiteConfig()
|
||||
.then((res) => {
|
||||
|
@ -321,6 +395,25 @@ export default {
|
|||
.catch(() => {});
|
||||
},
|
||||
methods: {
|
||||
handleRemove(file, index = undefined) {
|
||||
let id = file.id;
|
||||
if (file.response != null) {
|
||||
id = file.response.data.id;
|
||||
}
|
||||
api.admin_deleteHomeCarousel(id).then((res) => {
|
||||
myMessage.success(this.$i18n.t('m.Delete_successfully'));
|
||||
if (index != undefined) {
|
||||
this.carouselImgList.splice(index, 1);
|
||||
}
|
||||
});
|
||||
},
|
||||
handlePictureCardPreview(file) {
|
||||
this.dialogImageUrl = file.url;
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
handleDownload(file) {
|
||||
utils.downloadFile(file.url);
|
||||
},
|
||||
saveSMTPConfig() {
|
||||
api.admin_editSMTPConfig(this.smtp).then(
|
||||
(res) => {
|
||||
|
|
|
@ -83,8 +83,8 @@
|
|||
arrow="always"
|
||||
indicator-position="outside"
|
||||
>
|
||||
<el-carousel-item v-for="item in srcList" :key="item">
|
||||
<el-image :src="item" fit="fill"></el-image>
|
||||
<el-carousel-item v-for="item in carouselImgList" :key="item">
|
||||
<el-image :src="item.url" fit="fill"></el-image>
|
||||
</el-carousel-item>
|
||||
</el-carousel>
|
||||
</el-card>
|
||||
|
@ -224,7 +224,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
interval: 6000,
|
||||
interval: 4000,
|
||||
otherContests: [],
|
||||
recentUserACRecord: [],
|
||||
CONTEST_STATUS_REVERSE: {},
|
||||
|
@ -234,9 +234,13 @@ export default {
|
|||
recent7ACRankLoading: false,
|
||||
recentOtherContestsLoading: false,
|
||||
},
|
||||
srcList: [
|
||||
'https://cdn.jsdelivr.net/gh/HimitZH/CDN/images/home1.jfif',
|
||||
'https://cdn.jsdelivr.net/gh/HimitZH/CDN/images/home2.jpeg',
|
||||
carouselImgList: [
|
||||
{
|
||||
url: 'https://cdn.jsdelivr.net/gh/HimitZH/CDN/images/home1.jfif',
|
||||
},
|
||||
{
|
||||
url: 'https://cdn.jsdelivr.net/gh/HimitZH/CDN/images/home2.jpeg',
|
||||
},
|
||||
],
|
||||
srcHight: '440px',
|
||||
};
|
||||
|
@ -249,11 +253,20 @@ export default {
|
|||
this.srcHight = '440px';
|
||||
}
|
||||
this.CONTEST_STATUS_REVERSE = Object.assign({}, CONTEST_STATUS_REVERSE);
|
||||
this.getHomeCarousel();
|
||||
this.getRecentContests();
|
||||
this.getRecent7ACRank();
|
||||
this.getRecentOtherContests();
|
||||
},
|
||||
methods: {
|
||||
getHomeCarousel() {
|
||||
api.getHomeCarousel().then((res) => {
|
||||
if (res.data.data != null && res.data.data.length > 0) {
|
||||
this.carouselImgList = res.data.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getRecentContests() {
|
||||
api.getRecentContests().then((res) => {
|
||||
this.contests = res.data.data;
|
||||
|
|
|
@ -77,7 +77,6 @@
|
|||
</vxe-table-column>
|
||||
<vxe-table-column
|
||||
field="realname"
|
||||
fixed="left"
|
||||
min-width="96"
|
||||
:title="$t('m.RealName')"
|
||||
v-if="isContestAdmin"
|
||||
|
@ -128,9 +127,32 @@
|
|||
<span v-if="row.submissionInfo[problem.displayId].isAC"
|
||||
>{{ row.submissionInfo[problem.displayId].ACTime }}<br
|
||||
/></span>
|
||||
<span v-if="row.submissionInfo[problem.displayId].errorNum != 0"
|
||||
>(-{{ row.submissionInfo[problem.displayId].errorNum }})</span
|
||||
<span
|
||||
v-if="
|
||||
row.submissionInfo[problem.displayId].tryNum == null &&
|
||||
row.submissionInfo[problem.displayId].errorNum != 0
|
||||
"
|
||||
>
|
||||
(-{{
|
||||
row.submissionInfo[problem.displayId].errorNum > 0
|
||||
? row.submissionInfo[problem.displayId].errorNum
|
||||
: 0
|
||||
}})
|
||||
</span>
|
||||
<span v-if="row.submissionInfo[problem.displayId].tryNum != null"
|
||||
><template
|
||||
v-if="row.submissionInfo[problem.displayId].errorNum > 0"
|
||||
>
|
||||
(-{{
|
||||
row.submissionInfo[problem.displayId].errorNum
|
||||
}})+</template
|
||||
>({{ row.submissionInfo[problem.displayId].tryNum
|
||||
}}{{
|
||||
row.submissionInfo[problem.displayId].tryNum > 1
|
||||
? ' tries'
|
||||
: ' try'
|
||||
}})
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
</vxe-table-column>
|
||||
|
@ -301,6 +323,8 @@ export default {
|
|||
cellClass[problemID] = 'first-ac';
|
||||
} else if (status.isAC) {
|
||||
cellClass[problemID] = 'ac';
|
||||
} else if (status.tryNum != null && status.tryNum > 0) {
|
||||
cellClass[problemID] = 'try';
|
||||
} else if (status.errorNum != 0) {
|
||||
cellClass[problemID] = 'wa';
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue