feat(项目设置): 缺陷列表批量操作功能
This commit is contained in:
parent
f9168d17fe
commit
7844e3365c
|
@ -88,3 +88,5 @@ not_local_bug_error=非本地缺陷,无法操作
|
||||||
third_party_not_config=项目未配置第三方平台
|
third_party_not_config=项目未配置第三方平台
|
||||||
bug_attachment_upload_error=缺陷附件上传失败
|
bug_attachment_upload_error=缺陷附件上传失败
|
||||||
bug_attachment_delete_error=缺陷附件删除失败
|
bug_attachment_delete_error=缺陷附件删除失败
|
||||||
|
no_bug_select=未勾选缺陷
|
||||||
|
bug_select_not_found=未查询到勾选的缺陷
|
|
@ -88,3 +88,5 @@ not_local_bug_error=Not local bug, error
|
||||||
third_party_not_config=The project third-party platform not configured
|
third_party_not_config=The project third-party platform not configured
|
||||||
bug_attachment_upload_error=Bug attachment upload error
|
bug_attachment_upload_error=Bug attachment upload error
|
||||||
bug_attachment_delete_error=Bug attachment delete error
|
bug_attachment_delete_error=Bug attachment delete error
|
||||||
|
no_bug_select=No bug selected
|
||||||
|
bug_select_not_found=Selected bug not found
|
||||||
|
|
|
@ -88,3 +88,5 @@ not_local_bug_error=非本地缺陷,无法操作
|
||||||
third_party_not_config=项目未配置第三方平台
|
third_party_not_config=项目未配置第三方平台
|
||||||
bug_attachment_upload_error=缺陷附件上传失败
|
bug_attachment_upload_error=缺陷附件上传失败
|
||||||
bug_attachment_delete_error=缺陷附件删除失败
|
bug_attachment_delete_error=缺陷附件删除失败
|
||||||
|
no_bug_select=未勾选缺陷
|
||||||
|
bug_select_not_found=未查询到勾选的缺陷
|
|
@ -88,4 +88,6 @@ not_local_bug_error=非本地缺陷,無法操作
|
||||||
third_party_not_config=項目未配置第三方平台
|
third_party_not_config=項目未配置第三方平台
|
||||||
bug_attachment_upload_error=缺陷附件上傳失敗
|
bug_attachment_upload_error=缺陷附件上傳失敗
|
||||||
bug_attachment_delete_error=缺陷附件刪除失敗
|
bug_attachment_delete_error=缺陷附件刪除失敗
|
||||||
|
no_bug_select=未勾選缺陷
|
||||||
|
bug_select_not_found=未查詢到勾選的缺陷
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@ package io.metersphere.bug.controller;
|
||||||
import com.github.pagehelper.Page;
|
import com.github.pagehelper.Page;
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
import io.metersphere.bug.dto.BugDTO;
|
import io.metersphere.bug.dto.BugDTO;
|
||||||
|
import io.metersphere.bug.dto.request.BugBatchRequest;
|
||||||
|
import io.metersphere.bug.dto.request.BugBatchUpdateRequest;
|
||||||
import io.metersphere.bug.dto.request.BugEditRequest;
|
import io.metersphere.bug.dto.request.BugEditRequest;
|
||||||
import io.metersphere.bug.dto.request.BugPageRequest;
|
import io.metersphere.bug.dto.request.BugPageRequest;
|
||||||
import io.metersphere.bug.service.BugService;
|
import io.metersphere.bug.service.BugService;
|
||||||
|
@ -86,4 +88,18 @@ public class BugController {
|
||||||
public TemplateDTO getTemplateField(@PathVariable String id, @RequestParam(value = "projectId") String projectId) {
|
public TemplateDTO getTemplateField(@PathVariable String id, @RequestParam(value = "projectId") String projectId) {
|
||||||
return bugService.getTemplate(id, projectId);
|
return bugService.getTemplate(id, projectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/batch-delete")
|
||||||
|
@Operation(summary = "缺陷管理-批量删除缺陷")
|
||||||
|
@RequiresPermissions(PermissionConstants.BUG_DELETE)
|
||||||
|
public void batchDelete(@Validated @RequestBody BugBatchRequest request) {
|
||||||
|
bugService.batchDelete(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/batch-update")
|
||||||
|
@Operation(summary = "缺陷管理-批量编辑缺陷")
|
||||||
|
@RequiresPermissions(PermissionConstants.BUG_UPDATE)
|
||||||
|
public void batchUpdate(@Validated @RequestBody BugBatchUpdateRequest request) {
|
||||||
|
bugService.batchUpdate(request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
package io.metersphere.bug.controller;
|
|
||||||
|
|
||||||
public class BugHistoryController {
|
|
||||||
}
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package io.metersphere.bug.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class BugTagEditDTO {
|
||||||
|
|
||||||
|
@Schema(description = "缺陷ID")
|
||||||
|
private String bugId;
|
||||||
|
|
||||||
|
@Schema(description = "标签值")
|
||||||
|
private String tag;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package io.metersphere.bug.dto.request;
|
||||||
|
|
||||||
|
import io.metersphere.system.dto.sdk.BaseCondition;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class BugBatchRequest extends BaseCondition {
|
||||||
|
|
||||||
|
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private String projectId;
|
||||||
|
|
||||||
|
@Schema(description = "是否全选", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private boolean selectAll;
|
||||||
|
|
||||||
|
@Schema(description = "缺陷ID勾选集合")
|
||||||
|
private List<String> includeBugIds;
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package io.metersphere.bug.dto.request;
|
||||||
|
|
||||||
|
import io.metersphere.bug.dto.BugCustomFieldDTO;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class BugBatchUpdateRequest extends BugBatchRequest{
|
||||||
|
|
||||||
|
@Schema(description = "处理人")
|
||||||
|
private String handleUser;
|
||||||
|
|
||||||
|
@Schema(description = "标签")
|
||||||
|
private String tag;
|
||||||
|
|
||||||
|
@Schema(description = "自定义字段")
|
||||||
|
private BugCustomFieldDTO customField;
|
||||||
|
|
||||||
|
@Schema(description = "是否追加", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private boolean append;
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.Size;
|
import jakarta.validation.constraints.Size;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -14,6 +15,7 @@ import java.util.Map;
|
||||||
* @author song-cc-rock
|
* @author song-cc-rock
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class BugEditRequest {
|
public class BugEditRequest {
|
||||||
|
|
||||||
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package io.metersphere.bug.mapper;
|
package io.metersphere.bug.mapper;
|
||||||
|
|
||||||
import io.metersphere.bug.dto.BugDTO;
|
import io.metersphere.bug.dto.BugDTO;
|
||||||
|
import io.metersphere.bug.dto.BugTagEditDTO;
|
||||||
|
import io.metersphere.bug.dto.request.BugBatchUpdateRequest;
|
||||||
import io.metersphere.bug.dto.request.BugPageRequest;
|
import io.metersphere.bug.dto.request.BugPageRequest;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
@ -23,4 +25,18 @@ public interface ExtBugMapper {
|
||||||
* @return 最大的业务ID
|
* @return 最大的业务ID
|
||||||
*/
|
*/
|
||||||
Long getMaxNum(String projectId);
|
Long getMaxNum(String projectId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缺陷标签列表
|
||||||
|
* @param ids 缺陷ID集合
|
||||||
|
* @return 缺陷标签列表
|
||||||
|
*/
|
||||||
|
List<BugTagEditDTO> getBugTagList(@Param("ids") List<String> ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量更新缺陷
|
||||||
|
* @param request 请求参数
|
||||||
|
* @param ids 缺陷ID集合
|
||||||
|
*/
|
||||||
|
void batchUpdate(@Param("request") BugBatchUpdateRequest request, @Param("ids") List<String> ids);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,30 @@
|
||||||
select max(num) from bug where project_id = #{projectId}
|
select max(num) from bug where project_id = #{projectId}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="getBugTagList" resultType="io.metersphere.bug.dto.BugTagEditDTO">
|
||||||
|
select id as bugId, tag from bug where id in
|
||||||
|
<foreach collection="ids" item="id" separator="," open="(" close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<update id="batchUpdate" parameterType="io.metersphere.bug.dto.request.BugBatchUpdateRequest">
|
||||||
|
update bug
|
||||||
|
<set>
|
||||||
|
<if test="request.handleUser != null and request.handleUser != ''">
|
||||||
|
handle_user = #{request.handleUser},
|
||||||
|
handle_users = handle_users + concat(',', #{request.handleUser}),
|
||||||
|
</if>
|
||||||
|
<if test="request.tag != null and request.tag != ''">
|
||||||
|
tag = #{request.tag},
|
||||||
|
</if>
|
||||||
|
</set>
|
||||||
|
where id in
|
||||||
|
<foreach collection="ids" item="id" separator="," open="(" close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</update>
|
||||||
|
|
||||||
<sql id="queryWhereCondition">
|
<sql id="queryWhereCondition">
|
||||||
<where>
|
<where>
|
||||||
<if test="request.useTrash">
|
<if test="request.useTrash">
|
||||||
|
|
|
@ -4,6 +4,9 @@ import io.metersphere.bug.domain.*;
|
||||||
import io.metersphere.bug.dto.BugCustomFieldDTO;
|
import io.metersphere.bug.dto.BugCustomFieldDTO;
|
||||||
import io.metersphere.bug.dto.BugDTO;
|
import io.metersphere.bug.dto.BugDTO;
|
||||||
import io.metersphere.bug.dto.BugRelationCaseCountDTO;
|
import io.metersphere.bug.dto.BugRelationCaseCountDTO;
|
||||||
|
import io.metersphere.bug.dto.BugTagEditDTO;
|
||||||
|
import io.metersphere.bug.dto.request.BugBatchRequest;
|
||||||
|
import io.metersphere.bug.dto.request.BugBatchUpdateRequest;
|
||||||
import io.metersphere.bug.dto.request.BugEditRequest;
|
import io.metersphere.bug.dto.request.BugEditRequest;
|
||||||
import io.metersphere.bug.dto.request.BugPageRequest;
|
import io.metersphere.bug.dto.request.BugPageRequest;
|
||||||
import io.metersphere.bug.enums.BugPlatform;
|
import io.metersphere.bug.enums.BugPlatform;
|
||||||
|
@ -29,7 +32,6 @@ import io.metersphere.system.file.FileRequest;
|
||||||
import io.metersphere.system.mapper.BaseUserMapper;
|
import io.metersphere.system.mapper.BaseUserMapper;
|
||||||
import io.metersphere.system.mapper.TemplateMapper;
|
import io.metersphere.system.mapper.TemplateMapper;
|
||||||
import io.metersphere.system.service.BaseTemplateService;
|
import io.metersphere.system.service.BaseTemplateService;
|
||||||
import io.metersphere.system.service.PlatformPluginService;
|
|
||||||
import io.metersphere.system.uid.IDGenerator;
|
import io.metersphere.system.uid.IDGenerator;
|
||||||
import io.metersphere.system.uid.NumGenerator;
|
import io.metersphere.system.uid.NumGenerator;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
@ -69,8 +71,6 @@ public class BugService {
|
||||||
@Resource
|
@Resource
|
||||||
private SqlSessionFactory sqlSessionFactory;
|
private SqlSessionFactory sqlSessionFactory;
|
||||||
@Resource
|
@Resource
|
||||||
private PlatformPluginService platformPluginService;
|
|
||||||
@Resource
|
|
||||||
private ProjectTemplateService projectTemplateService;
|
private ProjectTemplateService projectTemplateService;
|
||||||
@Resource
|
@Resource
|
||||||
private BugCustomFieldMapper bugCustomFieldMapper;
|
private BugCustomFieldMapper bugCustomFieldMapper;
|
||||||
|
@ -141,7 +141,7 @@ public class BugService {
|
||||||
// 缺陷基础字段
|
// 缺陷基础字段
|
||||||
handleAndSaveBug(request, currentUser, BugPlatform.LOCAL.getName());
|
handleAndSaveBug(request, currentUser, BugPlatform.LOCAL.getName());
|
||||||
// 自定义字段
|
// 自定义字段
|
||||||
handleAndSaveCustomFields(request, false);
|
handleAndSaveCustomFields(request, false, false);
|
||||||
// 附件
|
// 附件
|
||||||
handleAndSaveAttachments(request, files, currentUser);
|
handleAndSaveAttachments(request, files, currentUser);
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,7 @@ public class BugService {
|
||||||
// 缺陷
|
// 缺陷
|
||||||
handleAndSaveBug(request, currentUser, BugPlatform.LOCAL.getName());
|
handleAndSaveBug(request, currentUser, BugPlatform.LOCAL.getName());
|
||||||
// 自定义字段
|
// 自定义字段
|
||||||
handleAndSaveCustomFields(request, true);
|
handleAndSaveCustomFields(request, true, false);
|
||||||
// 附件
|
// 附件
|
||||||
handleAndSaveAttachments(request, files, currentUser);
|
handleAndSaveAttachments(request, files, currentUser);
|
||||||
}
|
}
|
||||||
|
@ -214,6 +214,106 @@ public class BugService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除缺陷
|
||||||
|
* @param request 请求参数
|
||||||
|
*/
|
||||||
|
public void batchDelete(BugBatchRequest request) {
|
||||||
|
// 非Local直接删除, Local移入回收站
|
||||||
|
if (request.isSelectAll()) {
|
||||||
|
// 全选
|
||||||
|
BugPageRequest bugPageRequest = new BugPageRequest();
|
||||||
|
BeanUtils.copyBean(bugPageRequest, request);
|
||||||
|
bugPageRequest.setUseTrash(false);
|
||||||
|
CustomFieldUtils.setBaseQueryRequestCustomMultipleFields(bugPageRequest);
|
||||||
|
List<BugDTO> bugs = extBugMapper.list(bugPageRequest);
|
||||||
|
if (CollectionUtils.isNotEmpty(bugs)) {
|
||||||
|
List<String> deleteIds = bugs.stream().filter(bug -> !StringUtils.equals(BugPlatform.LOCAL.getName(), bug.getPlatform())).map(BugDTO::getId).toList();
|
||||||
|
if (CollectionUtils.isNotEmpty(deleteIds)) {
|
||||||
|
BugExample bugExample = new BugExample();
|
||||||
|
bugExample.createCriteria().andIdIn(deleteIds);
|
||||||
|
bugMapper.deleteByExample(bugExample);
|
||||||
|
}
|
||||||
|
bugs.stream().filter(bug -> StringUtils.equals(bug.getPlatform(), BugPlatform.LOCAL.getName())).forEach(bug -> {
|
||||||
|
Bug record = new Bug();
|
||||||
|
record.setId(bug.getId());
|
||||||
|
record.setTrash(true);
|
||||||
|
bugMapper.updateByPrimaryKeySelective(record);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 勾选部分
|
||||||
|
if (CollectionUtils.isEmpty(request.getIncludeBugIds())) {
|
||||||
|
throw new MSException(Translator.get("no_bug_select"));
|
||||||
|
}
|
||||||
|
// 勾选操作数据较少, 可逐条删除
|
||||||
|
request.getIncludeBugIds().forEach(this::delete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量编辑缺陷
|
||||||
|
* @param request 请求参数
|
||||||
|
*/
|
||||||
|
public void batchUpdate(BugBatchUpdateRequest request) {
|
||||||
|
List<String> handleIds = new ArrayList<>();
|
||||||
|
if (request.isSelectAll()) {
|
||||||
|
// 全选
|
||||||
|
BugPageRequest bugPageRequest = new BugPageRequest();
|
||||||
|
BeanUtils.copyBean(bugPageRequest, request);
|
||||||
|
bugPageRequest.setUseTrash(false);
|
||||||
|
CustomFieldUtils.setBaseQueryRequestCustomMultipleFields(bugPageRequest);
|
||||||
|
List<BugDTO> bugs = extBugMapper.list(bugPageRequest);
|
||||||
|
if (CollectionUtils.isNotEmpty(bugs)) {
|
||||||
|
handleIds = bugs.stream().map(BugDTO::getId).toList();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 勾选部分
|
||||||
|
if (CollectionUtils.isEmpty(request.getIncludeBugIds())) {
|
||||||
|
throw new MSException(Translator.get("no_bug_select"));
|
||||||
|
}
|
||||||
|
handleIds = request.getIncludeBugIds();
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isEmpty(handleIds)) {
|
||||||
|
throw new MSException(Translator.get("no_bug_select"));
|
||||||
|
}
|
||||||
|
if (request.getCustomField() == null) {
|
||||||
|
// 系统字段处理, TAG需单独处理追加的问题
|
||||||
|
if (StringUtils.isNotEmpty(request.getTag()) && request.isAppend()) {
|
||||||
|
// 标签(追加)
|
||||||
|
List<BugTagEditDTO> bugTagList = extBugMapper.getBugTagList(handleIds);
|
||||||
|
if (CollectionUtils.isEmpty(bugTagList)) {
|
||||||
|
throw new MSException(Translator.get("bug_select_not_found"));
|
||||||
|
}
|
||||||
|
Map<String, String> bugTagMap = bugTagList.stream().collect(Collectors.toMap(BugTagEditDTO::getBugId, b -> Optional.ofNullable(b.getTag()).orElse(StringUtils.EMPTY)));
|
||||||
|
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||||
|
BugMapper batchMapper = sqlSession.getMapper(BugMapper.class);
|
||||||
|
bugTagMap.forEach((k, v) -> {
|
||||||
|
Bug record = new Bug();
|
||||||
|
record.setId(k);
|
||||||
|
record.setTag(CustomFieldUtils.appendToMultipleCustomField(v, request.getTag()));
|
||||||
|
batchMapper.updateByPrimaryKeySelective(record);
|
||||||
|
});
|
||||||
|
sqlSession.flushStatements();
|
||||||
|
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
||||||
|
} else {
|
||||||
|
extBugMapper.batchUpdate(request, handleIds);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 自定义字段处理 (第三方模板字段暂时不支持批量编辑, 涉及到同步)
|
||||||
|
BugCustomFieldDTO customField = request.getCustomField();
|
||||||
|
Map<String, String> customFieldMap = new HashMap<>(1);
|
||||||
|
customFieldMap.put(customField.getId(), customField.getValue());
|
||||||
|
handleIds.forEach(id -> {
|
||||||
|
BugEditRequest bugEditRequest = new BugEditRequest();
|
||||||
|
BeanUtils.copyBean(bugEditRequest, request);
|
||||||
|
bugEditRequest.setId(id);
|
||||||
|
bugEditRequest.setCustomFieldMap(customFieldMap);
|
||||||
|
handleAndSaveCustomFields(bugEditRequest, true, request.isAppend());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理保存缺陷基础信息
|
* 处理保存缺陷基础信息
|
||||||
*
|
*
|
||||||
|
@ -283,7 +383,7 @@ public class BugService {
|
||||||
*
|
*
|
||||||
* @param request 请求参数
|
* @param request 请求参数
|
||||||
*/
|
*/
|
||||||
private void handleAndSaveCustomFields(BugEditRequest request, boolean merge) {
|
private void handleAndSaveCustomFields(BugEditRequest request, boolean merge, boolean append) {
|
||||||
Map<String, String> customFieldMap = request.getCustomFieldMap();
|
Map<String, String> customFieldMap = request.getCustomFieldMap();
|
||||||
if (MapUtils.isEmpty(customFieldMap)) {
|
if (MapUtils.isEmpty(customFieldMap)) {
|
||||||
return;
|
return;
|
||||||
|
@ -306,7 +406,12 @@ public class BugService {
|
||||||
// 已存在的缺陷字段关系
|
// 已存在的缺陷字段关系
|
||||||
bugCustomField.setBugId(request.getId());
|
bugCustomField.setBugId(request.getId());
|
||||||
bugCustomField.setFieldId(fieldId);
|
bugCustomField.setFieldId(fieldId);
|
||||||
bugCustomField.setValue(customFieldMap.get(fieldId));
|
if (append) {
|
||||||
|
// 追加处理只存在多选类型的自定义字段
|
||||||
|
bugCustomField.setValue(CustomFieldUtils.appendToMultipleCustomField(originalFieldMap.get(fieldId), customFieldMap.get(fieldId)));
|
||||||
|
} else {
|
||||||
|
bugCustomField.setValue(customFieldMap.get(fieldId));
|
||||||
|
}
|
||||||
updateFields.add(bugCustomField);
|
updateFields.add(bugCustomField);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -409,7 +514,9 @@ public class BugService {
|
||||||
addFiles.add(bugAttachment);
|
addFiles.add(bugAttachment);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
extBugAttachmentMapper.batchInsert(addFiles);
|
if (CollectionUtils.isNotEmpty(addFiles)) {
|
||||||
|
extBugAttachmentMapper.batchInsert(addFiles);
|
||||||
|
}
|
||||||
// TODO: 如果是第三方平台, 需调用平台插件同步上传附件
|
// TODO: 如果是第三方平台, 需调用平台插件同步上传附件
|
||||||
uploadMinioFiles.forEach((fileId, file) -> {
|
uploadMinioFiles.forEach((fileId, file) -> {
|
||||||
FileRequest fileRequest = new FileRequest();
|
FileRequest fileRequest = new FileRequest();
|
||||||
|
|
|
@ -60,4 +60,21 @@ public class CustomFieldUtils {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多选字段追加值
|
||||||
|
* @param originalVal 原始值
|
||||||
|
* @param appendVal 追加值
|
||||||
|
* @return 追加后的值
|
||||||
|
*/
|
||||||
|
public static String appendToMultipleCustomField(String originalVal, String appendVal) {
|
||||||
|
if (StringUtils.isEmpty(originalVal)) {
|
||||||
|
return appendVal;
|
||||||
|
}
|
||||||
|
List<String> orignalList = JSON.parseArray(originalVal, String.class);
|
||||||
|
List<String> appendList = JSON.parseArray(appendVal, String.class);
|
||||||
|
orignalList.addAll(appendList);
|
||||||
|
// 追加后需去重
|
||||||
|
return JSON.toJSONString(orignalList.stream().distinct().toList());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package io.metersphere.bug.controller;
|
package io.metersphere.bug.controller;
|
||||||
|
|
||||||
|
import io.metersphere.bug.dto.BugCustomFieldDTO;
|
||||||
import io.metersphere.bug.dto.BugDTO;
|
import io.metersphere.bug.dto.BugDTO;
|
||||||
|
import io.metersphere.bug.dto.request.BugBatchRequest;
|
||||||
|
import io.metersphere.bug.dto.request.BugBatchUpdateRequest;
|
||||||
import io.metersphere.bug.dto.request.BugEditRequest;
|
import io.metersphere.bug.dto.request.BugEditRequest;
|
||||||
import io.metersphere.bug.dto.request.BugPageRequest;
|
import io.metersphere.bug.dto.request.BugPageRequest;
|
||||||
import io.metersphere.project.dto.ProjectTemplateOptionDTO;
|
import io.metersphere.project.dto.ProjectTemplateOptionDTO;
|
||||||
|
@ -16,6 +19,7 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.test.context.jdbc.Sql;
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
import org.springframework.test.context.jdbc.SqlConfig;
|
import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
import org.springframework.test.web.servlet.MvcResult;
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -35,6 +39,8 @@ public class BugControllerTests extends BaseTest {
|
||||||
public static final String BUG_DELETE = "/bug/delete";
|
public static final String BUG_DELETE = "/bug/delete";
|
||||||
public static final String BUG_TEMPLATE_OPTION = "/bug/template/option";
|
public static final String BUG_TEMPLATE_OPTION = "/bug/template/option";
|
||||||
public static final String BUG_TEMPLATE_DETAIL = "/bug/template";
|
public static final String BUG_TEMPLATE_DETAIL = "/bug/template";
|
||||||
|
public static final String BUG_BATCH_DELETE = "/bug/batch-delete";
|
||||||
|
public static final String BUG_BATCH_UPDATE = "/bug/batch-update";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(0)
|
@Order(0)
|
||||||
|
@ -165,6 +171,11 @@ public class BugControllerTests extends BaseTest {
|
||||||
File file = new File(filePath);
|
File file = new File(filePath);
|
||||||
MultiValueMap<String, Object> paramMap = getDefaultMultiPartParam(request, file);
|
MultiValueMap<String, Object> paramMap = getDefaultMultiPartParam(request, file);
|
||||||
this.requestMultipartWithOkAndReturn(BUG_UPDATE, paramMap);
|
this.requestMultipartWithOkAndReturn(BUG_UPDATE, paramMap);
|
||||||
|
// 第二次更新, no-file
|
||||||
|
MultiValueMap<String, Object> noFileParamMap = new LinkedMultiValueMap<>();
|
||||||
|
request.setLinkFileIds(null);
|
||||||
|
noFileParamMap.add("request", JSON.toJSONString(request));
|
||||||
|
this.requestMultipartWithOkAndReturn(BUG_UPDATE, noFileParamMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -191,20 +202,6 @@ public class BugControllerTests extends BaseTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(8)
|
@Order(8)
|
||||||
public void testDeleteBugSuccess() throws Exception {
|
|
||||||
this.requestGet(BUG_DELETE + "/default-bug-id", status().isOk());
|
|
||||||
// 非Local缺陷
|
|
||||||
this.requestGet(BUG_DELETE + "/default-bug-id-tapd", status().isOk());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Order(9)
|
|
||||||
public void testDeleteBugError() throws Exception {
|
|
||||||
this.requestGet(BUG_DELETE + "/default-bug-id-not-exist", status().is5xxServerError());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Order(10)
|
|
||||||
public void testGetBugTemplateOption() throws Exception {
|
public void testGetBugTemplateOption() throws Exception {
|
||||||
MvcResult mvcResult = this.requestGetWithOkAndReturn(BUG_TEMPLATE_OPTION + "?projectId=default-project-for-bug");
|
MvcResult mvcResult = this.requestGetWithOkAndReturn(BUG_TEMPLATE_OPTION + "?projectId=default-project-for-bug");
|
||||||
String sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
String sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||||
|
@ -215,7 +212,7 @@ public class BugControllerTests extends BaseTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(11)
|
@Order(9)
|
||||||
public void testGetBugTemplateDetailSuccess() throws Exception {
|
public void testGetBugTemplateDetailSuccess() throws Exception {
|
||||||
MvcResult mvcResult = this.requestGetWithOkAndReturn(BUG_TEMPLATE_DETAIL + "/default-bug-template-id" + "?projectId=default-project-for-bug");
|
MvcResult mvcResult = this.requestGetWithOkAndReturn(BUG_TEMPLATE_DETAIL + "/default-bug-template-id" + "?projectId=default-project-for-bug");
|
||||||
String sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
String sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||||
|
@ -232,6 +229,108 @@ public class BugControllerTests extends BaseTest {
|
||||||
Assertions.assertEquals("default-bug-template-id", defaultTemplate.getId());
|
Assertions.assertEquals("default-bug-template-id", defaultTemplate.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(10)
|
||||||
|
public void testBatchUpdateBugSuccess() throws Exception {
|
||||||
|
BugBatchUpdateRequest request = new BugBatchUpdateRequest();
|
||||||
|
request.setProjectId("default-project-for-bug");
|
||||||
|
// 全选, 编辑所有数据
|
||||||
|
request.setSelectAll(true);
|
||||||
|
// TAG追加
|
||||||
|
request.setTag(JSON.toJSONString(List.of("TAG", "TEST_TAG")));
|
||||||
|
request.setAppend(true);
|
||||||
|
this.requestPost(BUG_BATCH_UPDATE, request, status().isOk());
|
||||||
|
// TAG覆盖
|
||||||
|
request.setTag(JSON.toJSONString(List.of("A", "B")));
|
||||||
|
request.setAppend(false);
|
||||||
|
this.requestPost(BUG_BATCH_UPDATE, request, status().isOk());
|
||||||
|
// TAG追加
|
||||||
|
request.setTag(JSON.toJSONString(List.of("C", "D")));
|
||||||
|
request.setAppend(true);
|
||||||
|
this.requestPost(BUG_BATCH_UPDATE, request, status().isOk());
|
||||||
|
// 处理人修改
|
||||||
|
request.setTag(null);
|
||||||
|
request.setHandleUser("default-admin");
|
||||||
|
this.requestPost(BUG_BATCH_UPDATE, request, status().isOk());
|
||||||
|
// 自定义字段追加
|
||||||
|
BugCustomFieldDTO field = new BugCustomFieldDTO();
|
||||||
|
field.setId("test_field");
|
||||||
|
field.setValue(JSON.toJSONString(List.of("test1")));
|
||||||
|
request.setCustomField(field);
|
||||||
|
this.requestPost(BUG_BATCH_UPDATE, request, status().isOk());
|
||||||
|
// 自定义字段覆盖
|
||||||
|
request.setAppend(false);
|
||||||
|
this.requestPost(BUG_BATCH_UPDATE, request, status().isOk());
|
||||||
|
// 勾选部分
|
||||||
|
request.setSelectAll(false);
|
||||||
|
request.setIncludeBugIds(List.of("default-bug-id"));
|
||||||
|
this.requestPost(BUG_BATCH_UPDATE, request, status().isOk());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(11)
|
||||||
|
public void testBatchUpdateEmptyBugSuccess() throws Exception {
|
||||||
|
BugBatchUpdateRequest request = new BugBatchUpdateRequest();
|
||||||
|
request.setProjectId("default-project-for-bug");
|
||||||
|
request.setCombine(buildRequestCombine());
|
||||||
|
// 全选, 空数据
|
||||||
|
request.setSelectAll(true);
|
||||||
|
request.setTag(JSON.toJSONString(List.of("TAG", "TEST_TAG")));
|
||||||
|
request.setAppend(true);
|
||||||
|
this.requestPost(BUG_BATCH_UPDATE, request, status().is5xxServerError());
|
||||||
|
request.setSelectAll(false);
|
||||||
|
request.setIncludeBugIds(List.of("not-exist-bug-id"));
|
||||||
|
this.requestPost(BUG_BATCH_UPDATE, request, status().is5xxServerError());
|
||||||
|
request.setSelectAll(false);
|
||||||
|
request.setIncludeBugIds(null);
|
||||||
|
this.requestPost(BUG_BATCH_UPDATE, request, status().is5xxServerError());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(12)
|
||||||
|
public void testDeleteBugSuccess() throws Exception {
|
||||||
|
this.requestGet(BUG_DELETE + "/default-bug-id", status().isOk());
|
||||||
|
// 非Local缺陷
|
||||||
|
this.requestGet(BUG_DELETE + "/default-bug-id-tapd1", status().isOk());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(13)
|
||||||
|
public void testDeleteBugError() throws Exception {
|
||||||
|
this.requestGet(BUG_DELETE + "/default-bug-id-not-exist", status().is5xxServerError());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(14)
|
||||||
|
public void testBatchDeleteEmptyBugSuccess() throws Exception {
|
||||||
|
BugBatchRequest request = new BugBatchRequest();
|
||||||
|
request.setProjectId("default-project-for-bug");
|
||||||
|
request.setCombine(buildRequestCombine());
|
||||||
|
// 全选, 空数据
|
||||||
|
request.setSelectAll(true);
|
||||||
|
this.requestPost(BUG_BATCH_DELETE, request, status().isOk());
|
||||||
|
// 勾选部分, 空数据
|
||||||
|
request.setSelectAll(false);
|
||||||
|
this.requestPost(BUG_BATCH_DELETE, request, status().is5xxServerError());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(20)
|
||||||
|
public void testBatchDeleteBugSuccess() throws Exception {
|
||||||
|
BugBatchRequest request = new BugBatchRequest();
|
||||||
|
request.setProjectId("default-project-for-bug");
|
||||||
|
// 全选, 删除所有
|
||||||
|
request.setSelectAll(true);
|
||||||
|
this.requestPost(BUG_BATCH_DELETE, request, status().isOk());
|
||||||
|
// 非Local的缺陷删除
|
||||||
|
request.setProjectId("default-project-for-bug-no-local");
|
||||||
|
this.requestPost(BUG_BATCH_DELETE, request, status().isOk());
|
||||||
|
// 勾选部分
|
||||||
|
request.setSelectAll(false);
|
||||||
|
request.setIncludeBugIds(List.of("default-bug-id-single"));
|
||||||
|
this.requestPost(BUG_BATCH_DELETE, request, status().isOk());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成请求过滤参数
|
* 生成请求过滤参数
|
||||||
* @return filter param
|
* @return filter param
|
||||||
|
@ -272,16 +371,15 @@ public class BugControllerTests extends BaseTest {
|
||||||
request.setHandleUser("admin");
|
request.setHandleUser("admin");
|
||||||
request.setTemplateId("default-bug-template");
|
request.setTemplateId("default-bug-template");
|
||||||
request.setStatus("prepare");
|
request.setStatus("prepare");
|
||||||
request.setTag(JSON.toJSONString(List.of("TAG", "DEFAULT-TAG")));
|
|
||||||
request.setLinkFileIds(List.of("default-bug-file-id-1", "default-bug-file-id-3"));
|
request.setLinkFileIds(List.of("default-bug-file-id-1", "default-bug-file-id-3"));
|
||||||
Map<String, String> customFieldMap = new HashMap<>();
|
Map<String, String> customFieldMap = new HashMap<>();
|
||||||
customFieldMap.put("custom-field", "oasis");
|
customFieldMap.put("custom-field", "oasis");
|
||||||
|
customFieldMap.put("test_field", JSON.toJSONString(List.of("test")));
|
||||||
if (isUpdate) {
|
if (isUpdate) {
|
||||||
request.setId("default-bug-id");
|
request.setId("default-bug-id");
|
||||||
request.setUnLinkFileIds(List.of("default-bug-file-id-1"));
|
request.setUnLinkFileIds(List.of("default-bug-file-id-1"));
|
||||||
request.setDeleteLocalFileIds(List.of("default-bug-file-id"));
|
request.setDeleteLocalFileIds(List.of("default-bug-file-id"));
|
||||||
request.setLinkFileIds(List.of("default-bug-file-id-2"));
|
request.setLinkFileIds(List.of("default-bug-file-id-2"));
|
||||||
customFieldMap.put("test_field", JSON.toJSONString(List.of("test")));
|
|
||||||
}
|
}
|
||||||
request.setCustomFieldMap(customFieldMap);
|
request.setCustomFieldMap(customFieldMap);
|
||||||
return request;
|
return request;
|
||||||
|
|
|
@ -7,12 +7,15 @@ INSERT INTO project (id, num, organization_id, name, description, create_user, u
|
||||||
INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_time,
|
INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_time,
|
||||||
update_user, update_time, delete_user, delete_time, project_id, template_id, platform, status, tag, platform_bug_id, trash) VALUES
|
update_user, update_time, delete_user, delete_time, project_id, template_id, platform, status, tag, platform_bug_id, trash) VALUES
|
||||||
('default-bug-id', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', 'bug-template-id', 'Local', 'open', 'default-tag', null, 0),
|
('default-bug-id', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', 'bug-template-id', 'Local', 'open', 'default-tag', null, 0),
|
||||||
('default-bug-id-tapd', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', 'default-bug-template-id', 'Tapd', 'open', 'default-tag', null, 0);
|
('default-bug-id-tapd1', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', 'default-bug-template-id', 'Tapd', 'open', 'default-tag', null, 0),
|
||||||
|
('default-bug-id-tapd2', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug-no-local', 'default-bug-template-id', 'Tapd', 'open', 'default-tag', null, 0),
|
||||||
|
('default-bug-id-single', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug-single', 'default-bug-template-id', 'Tapd', 'open', 'default-tag', null, 0);
|
||||||
|
|
||||||
INSERT INTO bug_custom_field (bug_id, field_id, value) VALUE ('default-bug-id', 'test_field', '["default", "default-1"]');
|
INSERT INTO bug_custom_field (bug_id, field_id, value) VALUE ('default-bug-id', 'test_field', '["default", "default-1"]');
|
||||||
|
|
||||||
INSERT INTO custom_field (id, name, scene, type, remark, internal, scope_type, create_time, update_time, create_user, scope_id) VALUE
|
INSERT INTO custom_field (id, name, scene, type, remark, internal, scope_type, create_time, update_time, create_user, scope_id) VALUE
|
||||||
('test_field', '测试字段', 'BUG', 'MULTIPLE_SELECT', '', 0, 'PROJECT', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'default-project-for-bug');
|
('test_field', '测试字段', 'BUG', 'MULTIPLE_SELECT', '', 0, 'PROJECT', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'default-project-for-bug'),
|
||||||
|
('custom-field', '测试字段', 'BUG', 'SELECT', '', 0, 'PROJECT', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'default-project-for-bug');
|
||||||
|
|
||||||
INSERT INTO template (id, name, remark, internal, update_time, create_time, create_user, scope_type, scope_id, enable_third_part, scene) VALUES
|
INSERT INTO template (id, name, remark, internal, update_time, create_time, create_user, scope_type, scope_id, enable_third_part, scene) VALUES
|
||||||
('bug-template-id', 'bug-template', '', 0, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', 'default-project-for-bug', 0, 'BUG'),
|
('bug-template-id', 'bug-template', '', 0, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', 'default-project-for-bug', 0, 'BUG'),
|
||||||
|
|
Loading…
Reference in New Issue