Compare commits

...

4 Commits

Author SHA1 Message Date
ArgonarioD 5d62c9af3a 修复了Task的查询问题,添加了交接接口和下载导入员工模板的接口,修改了导入员工的接口uri 2022-07-11 14:48:34 +08:00
ArgonarioD 90090bedf6 Merge remote-tracking branch 'origin/master' 2022-07-11 00:00:46 +08:00
ArgonarioD 8ed85fade0 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	src/main/java/cn/edu/hfut/rmdjzz/projectmanagement/service/impl/TaskServiceImpl.java
2022-07-10 23:22:09 +08:00
ArgonarioD fc481bdd17 修复了Task的查询问题 2022-07-09 11:56:48 +08:00
8 changed files with 141 additions and 15 deletions

View File

@ -11,6 +11,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
* @author * @author
* created at 2022/6/28 19:44 * created at 2022/6/28 19:44
*/ */
//TODO: 整机限流
@Configuration @Configuration
public class WebConfig implements WebMvcConfigurer { public class WebConfig implements WebMvcConfigurer {
@Bean @Bean

View File

@ -20,6 +20,7 @@ import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
/** /**
@ -122,4 +123,20 @@ public class ProjectGroupController {
} }
return ResponseList.ofSuccess(taskService.getProjectProcessOfStaff(token, projectId)); return ResponseList.ofSuccess(taskService.getProjectProcessOfStaff(token, projectId));
} }
//TODO: TEST
@Operation(description = "请求体是一个key为taskIdvalue为staffId的map")
@SneakyThrows
@PutMapping("/{staffId}/transfer")
public ResponseMap transferStaffTasks(
@RequestHeader("Token") String token,
@PathVariable Integer projectId,
@PathVariable Integer staffId,
@RequestBody Map<Long, Integer> transferMap
) {
if (taskService.transferStaffTasks(token, projectId, staffId, transferMap)) {
return ResponseMap.ofSuccess();
}
throw new BadRequestException(BadRequestException.OPERATE_FAILED);
}
} }

View File

@ -2,8 +2,11 @@ package cn.edu.hfut.rmdjzz.projectmanagement.controller;
import cn.edu.hfut.rmdjzz.projectmanagement.entity.Staff; import cn.edu.hfut.rmdjzz.projectmanagement.entity.Staff;
import cn.edu.hfut.rmdjzz.projectmanagement.exception.BadRequestException; import cn.edu.hfut.rmdjzz.projectmanagement.exception.BadRequestException;
import cn.edu.hfut.rmdjzz.projectmanagement.exception.ForbiddenException;
import cn.edu.hfut.rmdjzz.projectmanagement.exception.TokenException; import cn.edu.hfut.rmdjzz.projectmanagement.exception.TokenException;
import cn.edu.hfut.rmdjzz.projectmanagement.service.IStaffService; import cn.edu.hfut.rmdjzz.projectmanagement.service.IStaffService;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.FileUtils;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.TokenUtils;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.http.ResponseMap; import cn.edu.hfut.rmdjzz.projectmanagement.utils.http.ResponseMap;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import lombok.SneakyThrows; import lombok.SneakyThrows;
@ -12,6 +15,7 @@ import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects; import java.util.Objects;
/** /**
@ -43,8 +47,12 @@ public class StaffController {
} }
@SneakyThrows @SneakyThrows
@PostMapping(value = "/staff/import") @PostMapping(value = "/import")
public ResponseMap upload(@RequestHeader("Token") String token, @RequestParam("uploadFile") MultipartFile uploadFile,@RequestParam("digest") String digest) { public ResponseMap importStaffs(
@RequestHeader("Token") String token,
@RequestParam("File-Digest") String digest,
@RequestParam("uploadFile") MultipartFile uploadFile
) {
if (null == uploadFile) { if (null == uploadFile) {
throw new BadRequestException("文件传输错误"); throw new BadRequestException("文件传输错误");
} }
@ -52,10 +60,25 @@ public class StaffController {
if (!fileName.endsWith(".xlsx")) { if (!fileName.endsWith(".xlsx")) {
throw new BadRequestException("文件类型错误"); throw new BadRequestException("文件类型错误");
} }
if(!Objects.equals(DigestUtils.md5DigestAsHex(uploadFile.getBytes()).toLowerCase(),digest.toLowerCase())){ if (!Objects.equals(DigestUtils.md5DigestAsHex(uploadFile.getBytes()).toLowerCase(), digest.toLowerCase())) {
throw new BadRequestException("文件传输错误"); throw new BadRequestException("文件传输错误");
} }
Integer successCount = staffService.multiImport(token, uploadFile); Integer successCount = staffService.multiImport(token, uploadFile);
return ResponseMap.ofSuccess("成功导入" + successCount + "条数据"); return ResponseMap.ofSuccess("成功导入" + successCount + "条数据");
} }
@SneakyThrows
@GetMapping("/import/template")
public ResponseMap downloadTemplate(
@RequestHeader("Token") String token,
HttpServletResponse response
) {
if (TokenUtils.getStaffGlobalLevel(token) > 2) {
throw new ForbiddenException(ForbiddenException.UNABLE_TO_OPERATE);
}
if (FileUtils.downloadResource("static/账户导入模板.xlsx", response)) {
return ResponseMap.ofSuccess();
}
throw new BadRequestException(BadRequestException.OPERATE_FAILED);
}
} }

View File

@ -1,6 +1,5 @@
package cn.edu.hfut.rmdjzz.projectmanagement.entity; package cn.edu.hfut.rmdjzz.projectmanagement.entity;
import cn.edu.hfut.rmdjzz.projectmanagement.service.IProjectGroupService;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.BeanUtils; import cn.edu.hfut.rmdjzz.projectmanagement.utils.BeanUtils;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
@ -8,8 +7,8 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data; import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Map; import java.util.Map;
@ -19,19 +18,17 @@ import java.util.Objects;
* @author * @author
* @since 2022/7/4 11:07 * @since 2022/7/4 11:07
*/ */
@Builder
@Data @Data
public class Task { public class Task {
@Autowired
private IProjectGroupService projectGroupService;
public static final String ATTACH_DEMAND_SOURCE = "demandSource"; public static final String ATTACH_DEMAND_SOURCE = "demandSource";
public static final String ATTACH_ESTIMATED_MAN_HOURS = "estimatedManHours"; public static final String ATTACH_ESTIMATED_MAN_HOURS = "estimatedManHours";
public static final String ATTACH_SEVERITY = "severity"; public static final String ATTACH_SEVERITY = "severity";
public static final String ATTACH_RECURRENCE_PROBABILITY = "recurrenceProbability"; public static final String ATTACH_RECURRENCE_PROBABILITY = "recurrenceProbability";
public static final String TYPE_DEFECT = "缺陷"; public static final String TYPE_DEFECT = "缺陷";
public static final String TYPE_DEMAND = "需求"; public static final String TYPE_DEMAND = "需求";
public static final String TYPE_ASSIGNMENT = "任务"; public static final String TYPE_ASSIGNMENT = "任务";
public static final String STATUS_WAITING = "待进行"; public static final String STATUS_WAITING = "待进行";
public static final String STATUS_PROCESSING = "进行中"; public static final String STATUS_PROCESSING = "进行中";
public static final String STATUS_COMPLETED = "已完成"; public static final String STATUS_COMPLETED = "已完成";
@ -117,8 +114,6 @@ public class Task {
} }
public Boolean checkModification(Task rawTask) { public Boolean checkModification(Task rawTask) {
if (projectGroupService.getProjectAccessLevel(this.getTaskHolderId(), 3, this.getTaskProjectId()) == 0)
return false;
if (rawTask.getTaskStatus().equals(STATUS_COMPLETED) || rawTask.getTaskStatus().equals(STATUS_CLOSED)) if (rawTask.getTaskStatus().equals(STATUS_COMPLETED) || rawTask.getTaskStatus().equals(STATUS_CLOSED))
return false; return false;
if (!rawTask.getTaskStatus().equals(STATUS_WAITING) && this.getTaskStatus().equals(STATUS_WAITING)) if (!rawTask.getTaskStatus().equals(STATUS_WAITING) && this.getTaskStatus().equals(STATUS_WAITING))

View File

@ -45,4 +45,7 @@ public interface ITaskService extends IService<Task> {
Task modifyTask(String token, Task task) throws BadRequestException, ForbiddenException; Task modifyTask(String token, Task task) throws BadRequestException, ForbiddenException;
Map<String, List<TaskTrendDTO>> getProjectTaskTrend(String token, Integer projectId) throws BadRequestException, ForbiddenException; Map<String, List<TaskTrendDTO>> getProjectTaskTrend(String token, Integer projectId) throws BadRequestException, ForbiddenException;
Boolean transferStaffTasks(String token, Integer projectId, Integer transferredStaffId, Map<Long, Integer> transferMap) throws ForbiddenException, BadRequestException;
} }

View File

@ -12,6 +12,7 @@ import cn.edu.hfut.rmdjzz.projectmanagement.service.ITaskService;
import cn.edu.hfut.rmdjzz.projectmanagement.utils.TokenUtils; import cn.edu.hfut.rmdjzz.projectmanagement.utils.TokenUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SimpleQuery;
import lombok.NonNull; import lombok.NonNull;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -353,4 +354,57 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements IT
return taskTrendDTO; return taskTrendDTO;
} }
//不需要定义为事务因为updateBatch已经定义为事务
@Override
public Boolean transferStaffTasks(String token, Integer projectId, Integer transferredStaffId, Map<Long, Integer> transferMap) throws ForbiddenException, BadRequestException {
if (projectGroupService.getProjectAccessLevel(token, projectId) == 0
|| projectGroupService.getProjectAccessLevelIgnoreGlobalLevel(transferredStaffId, projectId) == 0) {
throw new ForbiddenException(IProjectGroupService.UNABLE_TO_ACCESS_PROJECT);
}
if (projectGroupService.compareProjectAccessLevel(projectId, token, transferredStaffId) < 0) {
throw new ForbiddenException(ForbiddenException.UNABLE_TO_OPERATE);
}
Map<Long, Task> originTransferTaskMap = SimpleQuery.keyMap(
Wrappers.<Task>lambdaQuery()
.eq(Task::getTaskProjectId, projectId)
.eq(Task::getTaskHolderId, transferredStaffId),
Task::getTaskId,
true
);
if (originTransferTaskMap.size() != transferMap.size()) {
throw new BadRequestException("未交接该员工的全部项目");
}
Set<Integer> targetStaffIdCache = new HashSet<>();
Set<Map.Entry<Long, Integer>> transferEntrySet = transferMap.entrySet();
for (Map.Entry<Long, Integer> transferEntry : transferEntrySet) {
Integer targetStaffId = transferEntry.getValue();
if (Objects.equals(targetStaffId, transferredStaffId)) {
throw new BadRequestException("不能将工作项交接给原员工");
}
if (!targetStaffIdCache.contains(targetStaffId)) {
if (projectGroupService.getProjectAccessLevelIgnoreGlobalLevel(targetStaffId, projectId) == 0) {
throw new BadRequestException("交接目标员工不在该项目组中");
}
targetStaffIdCache.add(targetStaffId);
}
Task targetTask = originTransferTaskMap.remove(transferEntry.getKey());
if (targetTask == null || !Objects.equals(targetTask.getTaskHolderId(), transferredStaffId)) {
throw new BadRequestException("指定的交接任务不属于该项目或被交接员工");
}
}
if (!originTransferTaskMap.isEmpty()) {
throw new BadRequestException("未交接该员工的全部项目");
}
return updateBatchById(
transferEntrySet.parallelStream()
.map(entry -> Task.builder()
.taskId(entry.getKey())
.taskHolderId(entry.getValue()).build())
.collect(Collectors.toList())
);
}
} }

View File

@ -0,0 +1,31 @@
package cn.edu.hfut.rmdjzz.projectmanagement.utils;
import lombok.Cleanup;
import org.springframework.util.DigestUtils;
import org.springframework.util.MimeTypeUtils;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
/**
* @author
* @since 2022/7/11 9:32
*/
public class FileUtils {
public static Boolean downloadResource(String resourceName, HttpServletResponse response) throws IOException {
@Cleanup InputStream is = FileUtils.class.getResourceAsStream(resourceName);
if (is == null) {
throw new FileNotFoundException("该文件不存在");
}
@Cleanup BufferedInputStream bis = new BufferedInputStream(is);
response.setContentType(MimeTypeUtils.APPLICATION_OCTET_STREAM_VALUE);
response.setCharacterEncoding("UTF-8");
ServletOutputStream out = response.getOutputStream();
response.addHeader("File-Digest", DigestUtils.md5DigestAsHex(bis));
@Cleanup BufferedOutputStream bos = new BufferedOutputStream(out);
bis.transferTo(bos);
bos.flush();
return true;
}
}

View File

@ -75,7 +75,13 @@ public class ResponseMap implements IResponse {
return of(HttpStatus.OK.value(), msg, data); return of(HttpStatus.OK.value(), msg, data);
} }
/**
* @param data Stringmsgdata
*/
public static ResponseMap ofSuccess(Object data) { public static ResponseMap ofSuccess(Object data) {
if (data instanceof String msg) {
return of(HttpStatus.OK.value(), msg);
}
return of(HttpStatus.OK.value(), SUCCESS, data); return of(HttpStatus.OK.value(), SUCCESS, data);
} }
@ -83,10 +89,6 @@ public class ResponseMap implements IResponse {
return of(HttpStatus.OK.value(), msg, data, putNulls); return of(HttpStatus.OK.value(), msg, data, putNulls);
} }
public static ResponseMap ofSuccess(String msg) {
return of(HttpStatus.OK.value(), msg);
}
public static ResponseMap ofSuccess() { public static ResponseMap ofSuccess() {
return of(HttpStatus.OK.value(), SUCCESS); return of(HttpStatus.OK.value(), SUCCESS);
} }