feat(用例管理): 批量复制&批量移动&表头/高级搜索自定义字段选项接口

This commit is contained in:
WangXu10 2023-11-08 19:24:54 +08:00 committed by Craftsman
parent ea1a654c5d
commit c322f69f2c
16 changed files with 387 additions and 19 deletions

View File

@ -11,6 +11,7 @@ import io.metersphere.functional.request.*;
import io.metersphere.functional.service.FunctionalCaseLogService;
import io.metersphere.functional.service.FunctionalCaseNoticeService;
import io.metersphere.functional.service.FunctionalCaseService;
import io.metersphere.project.dto.CustomFieldOptions;
import io.metersphere.project.service.ProjectTemplateService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.TemplateScene;
@ -144,4 +145,29 @@ public class FunctionalCaseController {
String userId = SessionUtils.getUserId();
functionalCaseService.batchDeleteFunctionalCaseToGc(request, userId);
}
@GetMapping("/custom/field/{projectId}")
@Operation(summary = "功能用例-获取表头自定义字段(高级搜索中的自定义字段)")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ)
public List<CustomFieldOptions> getTableCustomsField(@PathVariable String projectId) {
return projectTemplateService.getTableCustomsField(projectId, TemplateScene.FUNCTIONAL.name());
}
@PostMapping("/batch/move")
@Operation(summary = "功能用例-批量移动用例")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_UPDATE)
public void batchMoveFunctionalCase(@Validated @RequestBody FunctionalCaseBatchMoveRequest request) {
String userId = SessionUtils.getUserId();
functionalCaseService.batchMoveFunctionalCase(request, userId);
}
@PostMapping("/batch/copy")
@Operation(summary = "功能用例-批量复制用例")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_UPDATE)
public void batchCopyFunctionalCase(@Validated @RequestBody FunctionalCaseBatchMoveRequest request) {
String userId = SessionUtils.getUserId();
functionalCaseService.batchCopyFunctionalCase(request, userId);
}
}

View File

@ -26,6 +26,9 @@ public class FunctionalCaseDetailDTO implements Serializable {
@Schema(description = "模块ID")
private String moduleId;
@Schema(description = "模块名称")
private String moduleName;
@Schema(description = "项目ID")
private String projectId;

View File

@ -3,6 +3,7 @@ package io.metersphere.functional.mapper;
import io.metersphere.functional.domain.FunctionalCase;
import io.metersphere.functional.dto.FunctionalCasePageDTO;
import io.metersphere.functional.dto.FunctionalCaseVersionDTO;
import io.metersphere.functional.request.FunctionalCaseBatchMoveRequest;
import io.metersphere.functional.request.FunctionalCasePageRequest;
import io.metersphere.system.dto.table.TableBatchProcessDTO;
import org.apache.ibatis.annotations.Param;
@ -38,4 +39,6 @@ public interface ExtFunctionalCaseMapper {
List<FunctionalCase> getLogInfo(@Param("ids") List<String> ids);
List<String> getRefIds(@Param("ids") List<String> ids);
void batchMoveModule(@Param("request") FunctionalCaseBatchMoveRequest request, @Param("ids") List<String> ids, @Param("userId") String userId);
}

View File

@ -72,6 +72,7 @@
id,
num,
NAME,
module_id,
version_id,
create_user,
create_time,
@ -212,7 +213,7 @@
and ${versionTable}.ref_id = #{request.refId}
</if>
<if test="request.versionId == null and request.refId == null">
AND ${versionTable}.latest = 0
AND ${versionTable}.latest = 1
</if>
</sql>
@ -289,4 +290,18 @@
</foreach>
and deleted = false
</select>
<update id="batchMoveModule">
update functional_case
set module_id = #{request.moduleId},
update_user = #{userId},
update_time = UNIX_TIMESTAMP()*1000
where ref_id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
and deleted = false
and project_id = #{request.projectId}
</update>
</mapper>

View File

@ -0,0 +1,16 @@
package io.metersphere.functional.request;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author wx
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class FunctionalCaseBatchMoveRequest extends FunctionalCaseBatchRequest {
@Schema(description = "模块ID", requiredMode = Schema.RequiredMode.REQUIRED)
private String moduleId;
}

View File

@ -27,7 +27,10 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
@ -197,4 +200,26 @@ public class FunctionalCaseAttachmentService {
functionalCaseAttachmentMapper.deleteByExample(example);
deleteMinioFile(localAttachment, projectId);
}
/**
* 通过caseId获取附件信息
*
* @param ids
* @return
*/
public Map<String, List<FunctionalCaseAttachment>> getAttachmentByCaseIds(List<String> ids) {
FunctionalCaseAttachmentExample example = new FunctionalCaseAttachmentExample();
example.createCriteria().andCaseIdIn(ids);
List<FunctionalCaseAttachment> caseAttachments = functionalCaseAttachmentMapper.selectByExample(example);
Map<String, List<FunctionalCaseAttachment>> attachmentMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(caseAttachments)) {
attachmentMap = caseAttachments.stream().collect(Collectors.groupingBy(FunctionalCaseAttachment::getCaseId));
}
return attachmentMap;
}
public void batchSaveAttachment(List<FunctionalCaseAttachment> attachments) {
functionalCaseAttachmentMapper.batchInsert(attachments);
}
}

View File

@ -12,6 +12,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@ -107,4 +108,17 @@ public class FunctionalCaseCustomFieldService {
public List<FunctionalCaseCustomField> getCustomFieldByCaseIds(List<String> ids) {
return extFunctionalCaseCustomFieldMapper.getCustomFieldByCaseIds(ids);
}
public Map<String, List<FunctionalCaseCustomField>> getCustomFieldMapByCaseIds(List<String> ids) {
List<FunctionalCaseCustomField> customFieldList = getCustomFieldByCaseIds(ids);
Map<String, List<FunctionalCaseCustomField>> caseCustomFieldMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(customFieldList)) {
caseCustomFieldMap = customFieldList.stream().collect(Collectors.groupingBy(FunctionalCaseCustomField::getCaseId));
}
return caseCustomFieldMap;
}
public void batchSaveCustomField(List<FunctionalCaseCustomField> customFields) {
functionalCaseCustomFieldMapper.batchInsert(customFields);
}
}

View File

@ -26,6 +26,10 @@ import io.metersphere.system.uid.NumGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
@ -67,6 +71,9 @@ public class FunctionalCaseService {
@Resource
private DeleteFunctionalCaseService deleteFunctionalCaseService;
@Resource
SqlSessionFactory sqlSessionFactory;
public FunctionalCase addFunctionalCase(FunctionalCaseAddRequest request, List<MultipartFile> files, String userId) {
String caseId = IDGenerator.nextStr();
//添加功能用例
@ -407,4 +414,121 @@ public class FunctionalCaseService {
return request.getSelectIds();
}
}
/**
* 批量移动用例
*
* @param request
* @param userId
*/
public void batchMoveFunctionalCase(FunctionalCaseBatchMoveRequest request, String userId) {
List<String> ids = doSelectIds(request, request.getProjectId());
if (CollectionUtils.isNotEmpty(ids)) {
List<String> refId = extFunctionalCaseMapper.getRefIds(ids);
extFunctionalCaseMapper.batchMoveModule(request, refId, userId);
}
}
/**
* 批量复制用例
*
* @param request
* @param userId
*/
public void batchCopyFunctionalCase(FunctionalCaseBatchMoveRequest request, String userId) {
List<String> ids = doSelectIds(request, request.getProjectId());
if (CollectionUtils.isNotEmpty(ids)) {
//基本信息
Map<String, FunctionalCase> functionalCaseMap = copyBaseInfo(request.getProjectId(), ids);
//大字段
Map<String, FunctionalCaseBlob> functionalCaseBlobMap = copyBlobInfo(ids);
//附件 本地附件
Map<String, List<FunctionalCaseAttachment>> attachmentMap = functionalCaseAttachmentService.getAttachmentByCaseIds(ids);
//TODO 文件库附件
//自定义字段
Map<String, List<FunctionalCaseCustomField>> customFieldMap = functionalCaseCustomFieldService.getCustomFieldMapByCaseIds(ids);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
FunctionalCaseMapper mapper = sqlSession.getMapper(FunctionalCaseMapper.class);
Long nextOrder = getNextOrder(request.getProjectId());
try {
for (int i = 0; i < ids.size(); i++) {
String id = IDGenerator.nextStr();
FunctionalCase functionalCase = functionalCaseMap.get(ids.get(i));
FunctionalCaseBlob functionalCaseBlob = functionalCaseBlobMap.get(ids.get(i));
List<FunctionalCaseAttachment> caseAttachments = attachmentMap.get(ids.get(i));
List<FunctionalCaseCustomField> customFields = customFieldMap.get(ids.get(i));
Optional.ofNullable(functionalCase).ifPresent(functional -> {
functional.setId(id);
functional.setRefId(id);
functional.setModuleId(request.getModuleId());
functional.setNum(getNextNum(request.getProjectId()));
functional.setName(getCopyName(functionalCase.getName()));
functional.setReviewStatus(FunctionalCaseReviewStatus.UN_REVIEWED.name());
functional.setPos(nextOrder + ORDER_STEP);
functional.setLastExecuteResult(FunctionalCaseExecuteResult.UN_EXECUTED.name());
functional.setCreateUser(userId);
functional.setCreateTime(System.currentTimeMillis());
functional.setUpdateTime(System.currentTimeMillis());
mapper.insert(functional);
functionalCaseBlob.setId(id);
functionalCaseBlobMapper.insert(functionalCaseBlob);
});
if (CollectionUtils.isNotEmpty(caseAttachments)) {
caseAttachments.stream().forEach(attachment -> {
attachment.setId(IDGenerator.nextStr());
attachment.setCaseId(id);
attachment.setCreateUser(userId);
attachment.setCreateTime(System.currentTimeMillis());
});
functionalCaseAttachmentService.batchSaveAttachment(caseAttachments);
}
if (CollectionUtils.isNotEmpty(customFields)) {
customFields.stream().forEach(customField -> {
customField.setCaseId(id);
});
functionalCaseCustomFieldService.batchSaveCustomField(customFields);
}
if (i % 50 == 0) {
sqlSession.flushStatements();
}
}
sqlSession.flushStatements();
} finally {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
}
private String getCopyName(String name) {
String copyName = "copy_" + name + "_" + UUID.randomUUID().toString().substring(0, 4);
if (copyName.length() > 255) {
copyName = copyName.substring(0, 250) + copyName.substring(copyName.length() - 5);
}
return copyName;
}
private Map<String, FunctionalCaseBlob> copyBlobInfo(List<String> ids) {
FunctionalCaseBlobExample blobExample = new FunctionalCaseBlobExample();
blobExample.createCriteria().andIdIn(ids);
List<FunctionalCaseBlob> functionalCaseBlobs = functionalCaseBlobMapper.selectByExampleWithBLOBs(blobExample);
Map<String, FunctionalCaseBlob> functionalCaseBlobMap = functionalCaseBlobs.stream().collect(Collectors.toMap(FunctionalCaseBlob::getId, functionalCaseBlob -> functionalCaseBlob));
return functionalCaseBlobMap;
}
private Map<String, FunctionalCase> copyBaseInfo(String projectId, List<String> ids) {
FunctionalCaseExample example = new FunctionalCaseExample();
example.createCriteria().andProjectIdEqualTo(projectId).andDeletedEqualTo(false).andIdIn(ids);
List<FunctionalCase> functionalCaseLists = functionalCaseMapper.selectByExample(example);
Map<String, FunctionalCase> functionalMap = functionalCaseLists.stream().collect(Collectors.toMap(FunctionalCase::getId, functionalCase -> functionalCase));
return functionalMap;
}
}

View File

@ -45,6 +45,9 @@ public class FunctionalCaseControllerTests extends BaseTest {
public static final String FUNCTIONAL_CASE_DELETE_URL = "/functional/case/delete";
public static final String FUNCTIONAL_CASE_LIST_URL = "/functional/case/page";
public static final String FUNCTIONAL_CASE_BATCH_DELETE_URL = "/functional/case/batch/delete-to-gc";
public static final String FUNCTIONAL_CASE_TABLE_URL = "/functional/case/custom/field/";
public static final String FUNCTIONAL_CASE_BATCH_MOVE_URL = "/functional/case/batch/move";
public static final String FUNCTIONAL_CASE_BATCH_COPY_URL = "/functional/case/batch/copy";
@Resource
private NotificationMapper notificationMapper;
@ -280,7 +283,7 @@ public class FunctionalCaseControllerTests extends BaseTest {
@Test
@Order(6)
@Order(19)
public void testDeleteFunctionalCase() throws Exception {
FunctionalCaseDeleteRequest request = new FunctionalCaseDeleteRequest();
request.setId("TEST_FUNCTIONAL_CASE_ID");
@ -301,7 +304,7 @@ public class FunctionalCaseControllerTests extends BaseTest {
@Test
@Order(7)
@Order(20)
public void testBatchDelete() throws Exception {
FunctionalCaseBatchRequest request = new FunctionalCaseBatchRequest();
request.setProjectId(DEFAULT_PROJECT_ID);
@ -315,4 +318,37 @@ public class FunctionalCaseControllerTests extends BaseTest {
this.requestPostWithOkAndReturn(FUNCTIONAL_CASE_BATCH_DELETE_URL, request);
}
@Test
@Order(7)
public void testTableCustomField() throws Exception {
this.requestGetWithOkAndReturn(FUNCTIONAL_CASE_TABLE_URL + DEFAULT_PROJECT_ID);
}
@Test
@Order(4)
public void testBatchMove() throws Exception {
FunctionalCaseBatchMoveRequest request = new FunctionalCaseBatchMoveRequest();
request.setProjectId(DEFAULT_PROJECT_ID);
request.setModuleId("TEST_MOVE_MODULE_ID");
request.setSelectAll(false);
this.requestPostWithOkAndReturn(FUNCTIONAL_CASE_BATCH_MOVE_URL, request);
request.setSelectAll(true);
this.requestPostWithOkAndReturn(FUNCTIONAL_CASE_BATCH_MOVE_URL, request);
}
@Test
@Order(2)
public void testBatchCopy() throws Exception {
FunctionalCaseBatchMoveRequest request = new FunctionalCaseBatchMoveRequest();
request.setProjectId(DEFAULT_PROJECT_ID);
request.setModuleId("TEST_MOVE_MODULE_ID");
request.setSelectIds(Arrays.asList("TEST"));
request.setSelectAll(false);
this.requestPostWithOkAndReturn(FUNCTIONAL_CASE_BATCH_COPY_URL, request);
request.setSelectIds(new ArrayList<>());
request.setSelectAll(true);
this.requestPostWithOkAndReturn(FUNCTIONAL_CASE_BATCH_COPY_URL, request);
}
}

View File

@ -13,6 +13,9 @@ VALUES ('xiaomeinvGTestOne', 1000001, 'test_guo', '100001100001', 'test_guo', 'g
1698058347559,
null);
INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('xiaomeinvGTest', 'STEP', '1111', NULL, NULL, 'TEST');
INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('xiaomeinvGTestOne', 'STEP', '1111', NULL, NULL, 'TEST');
INSERT INTO user(id, name, email, password, create_time, update_time, language, last_organization_id, phone, source,
last_project_id, create_user, update_user, deleted)
VALUES ('default-project-member-user-guo', 'default-project-member-user1', 'project-member-guo1@metersphere.io',

View File

@ -26,4 +26,11 @@ INSERT INTO custom_field(id, name, scene, `type`, remark, internal, scope_type,
VALUES('gyq_custom_id2', 'level', 'FUNCTIONAL', 'SELECT', '', 1, 'ORGANIZATION', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', '100001');
INSERT INTO functional_case_comment(id, case_id, create_user, status, parent_id, resource_id, notifier, content, reply_user, create_time, update_time)
VALUES ('trash_comment_id', 'Trash_TEST_FUNCTIONAL_CASE_ID', 'gyq', null, null, null, 'gyq','你好', null, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000);
VALUES ('trash_comment_id', 'Trash_TEST_FUNCTIONAL_CASE_ID', 'gyq', null, null, null, 'gyq','你好', null, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000);
INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('Trash_TEST_FUNCTIONAL_CASE_ID', 'STEP', '1111', NULL, NULL, 'TEST');
INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('Trash_TEST_FUNCTIONAL_CASE_ID_1', 'STEP', '1111', NULL, NULL, 'TEST');
INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('Trash_TEST_FUNCTIONAL_CASE_ID_2', 'STEP', '1111', NULL, NULL, 'TEST');
INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('Trash_TEST_FUNCTIONAL_CASE_ID_3', 'STEP', '1111', NULL, NULL, 'TEST');
INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('Trash_TEST_FUNCTIONAL_CASE_ID_4', 'STEP', '1111', NULL, NULL, 'TEST');

View File

@ -2,30 +2,37 @@ INSERT INTO file_metadata(id, name, type, size, create_time, update_time, projec
INSERT INTO file_metadata(id, name, type, size, create_time, update_time, project_id, storage, create_user, update_user, tags, description, module_id, path, latest, ref_id, file_version) VALUES ('relate_file_meta_id_2', 'formItem', 'ts', 2502, 1698058347559, 1698058347559, '100001100001', 'MINIO', 'admin', 'admin', NULL, NULL, 'root', '100001100001/1127016598347779', b'1', '1127016598347779', '1127016598347779');
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
VALUES ('TEST_FUNCTIONAL_CASE_ID', 1, 'TEST_MOUDLE_ID', '100001100001', '100001', '测试', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'v1.0.0', 'UN_EXECUTED', b'0', b'0', b'0', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
VALUES ('TEST_FUNCTIONAL_CASE_ID', 1, 'TEST_MOUDLE_ID', '100001100001', '100001', '测试', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'v1.0.0', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
VALUES ('TEST_FUNCTIONAL_CASE_ID_1', 2, 'TEST_MOUDLE_ID', '100001100001', '100001', '测试多版本', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'TEST_REF_ID', 'UN_EXECUTED', b'0', b'0', b'0', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
VALUES ('TEST_FUNCTIONAL_CASE_ID_1', 2, 'TEST_MOUDLE_ID', '100001100001', '100001', '测试多版本', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'TEST_REF_ID', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
VALUES ('TEST_FUNCTIONAL_CASE_ID_2', 3, 'TEST_MOUDLE_ID', '100001100001', '100001', 'copy_测试多版本', 'UN_REVIEWED', NULL, 'STEP', 0, 'v2.0.0', 'TEST_REF_ID', 'UN_EXECUTED', b'0', b'0', b'0', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
VALUES ('TEST_FUNCTIONAL_CASE_ID_2', 3, 'TEST_MOUDLE_ID', '100001100001', '100001', 'copy_测试多版本', 'UN_REVIEWED', NULL, 'STEP', 0, 'v2.0.0', 'TEST_REF_ID', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
VALUES ('TEST_FUNCTIONAL_CASE_ID_3', 3, 'TEST_MOUDLE_ID', '100001100001', '100001', 'copy_测试多版本', 'UN_REVIEWED', NULL, 'STEP', 0, 'v3.0.0', 'TEST_REF_ID', 'UN_EXECUTED', b'0', b'0', b'0', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
VALUES ('TEST_FUNCTIONAL_CASE_ID_3', 3, 'TEST_MOUDLE_ID', '100001100001', '100001', 'copy_测试多版本', 'UN_REVIEWED', NULL, 'STEP', 0, 'v3.0.0', 'TEST_REF_ID', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
VALUES ('TEST_FUNCTIONAL_CASE_ID_4', 4, 'TEST_MOUDLE_ID', '100001100001', '100001', 'copy_测试多版本', 'UN_REVIEWED', NULL, 'STEP', 0, 'v3.0.0', 'TEST_REF_ID', 'UN_EXECUTED', b'0', b'0', b'0', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
VALUES ('TEST_FUNCTIONAL_CASE_ID_4', 4, 'TEST_MOUDLE_ID', '100001100001', '100001', 'copy_测试多版本', 'UN_REVIEWED', NULL, 'STEP', 0, 'v3.0.0', 'TEST_REF_ID', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
VALUES ('TEST_FUNCTIONAL_CASE_ID_5', 5, 'TEST_MOUDLE_ID', '100001100001', '100001', 'copy_测试多版本', 'UN_REVIEWED', NULL, 'STEP', 0, 'v3.0.0', 'TEST_REF_ID_1', 'UN_EXECUTED', b'0', b'0', b'0', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
VALUES ('TEST_FUNCTIONAL_CASE_ID_5', 5, 'TEST_MOUDLE_ID', '100001100001', '100001', 'copy_测试多版本', 'UN_REVIEWED', NULL, 'STEP', 0, 'v3.0.0', 'TEST_REF_ID_1', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
VALUES ('TEST_FUNCTIONAL_CASE_ID_6', 6, 'TEST_MOUDLE_ID', '100001100001', '100001', 'copy_测试多版本', 'UN_REVIEWED', NULL, 'STEP', 0, 'v3.0.0', 'TEST_REF_ID_1', 'UN_EXECUTED', b'0', b'0', b'0', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
VALUES ('TEST_FUNCTIONAL_CASE_ID_6', 6, 'TEST_MOUDLE_ID', '100001100001', '100001', 'copy_测试多版本', 'UN_REVIEWED', NULL, 'STEP', 0, 'v3.0.0', 'TEST_REF_ID_1', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
VALUES ('TEST_FUNCTIONAL_CASE_ID_7', 7, 'TEST_MOUDLE_ID', '100001100001', '100001', 'copy_测试多版本', 'UN_REVIEWED', NULL, 'STEP', 0, 'v3.0.0', 'TEST_REF_ID_2', 'UN_EXECUTED', b'0', b'0', b'0', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
VALUES ('TEST_FUNCTIONAL_CASE_ID_7', 7, 'TEST_MOUDLE_ID', '100001100001', '100001', 'copy_测试多版本', 'UN_REVIEWED', NULL, 'STEP', 0, 'v3.0.0', 'TEST_REF_ID_2', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL);
INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('TEST_FUNCTIONAL_CASE_ID', 'STEP', '1111', NULL, NULL, 'TEST');
INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('TEST_FUNCTIONAL_CASE_ID_1', 'STEP', '1111', NULL, NULL, '1111');
INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('TEST_FUNCTIONAL_CASE_ID_2', 'STEP', '2222', NULL, NULL, '2222');
INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('TEST_FUNCTIONAL_CASE_ID_3', 'STEP', '3333', NULL, NULL, '3333');
INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('TEST_FUNCTIONAL_CASE_ID_4', 'STEP', '4444', NULL, NULL, '4444');
INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('TEST_FUNCTIONAL_CASE_ID_5', 'STEP', '5555', NULL, NULL, '5555');
INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('TEST_FUNCTIONAL_CASE_ID_6', 'STEP', '6666', NULL, NULL, '6666');
INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('TEST_FUNCTIONAL_CASE_ID_7', 'STEP', '7777', NULL, NULL, '7777');
INSERT INTO functional_case_custom_field(case_id, field_id, value) VALUES ('TEST_FUNCTIONAL_CASE_ID', '100548878725546079', '22');

View File

@ -0,0 +1,32 @@
package io.metersphere.project.dto;
import io.metersphere.system.domain.CustomFieldOption;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* @author wx
*/
@Data
public class CustomFieldOptions implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "ID")
private String id;
@Schema(description = "自定义字段名称")
private String name;
@Schema(description = "自定义字段类型")
private String type;
@Schema(description = "是否内置字段")
private Boolean internal;
@Schema(description = "自定义字段选项值")
private List<CustomFieldOption> options;
}

View File

@ -3,27 +3,27 @@ package io.metersphere.project.service;
import io.metersphere.plugin.platform.spi.Platform;
import io.metersphere.plugin.sdk.spi.MsPlugin;
import io.metersphere.project.domain.ProjectApplication;
import io.metersphere.project.dto.CustomFieldOptions;
import io.metersphere.project.dto.ProjectTemplateDTO;
import io.metersphere.project.dto.ProjectTemplateOptionDTO;
import io.metersphere.sdk.constants.InternalUser;
import io.metersphere.sdk.constants.ProjectApplicationType;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.sdk.constants.TemplateScopeType;
import io.metersphere.system.dto.sdk.TemplateDTO;
import io.metersphere.system.dto.sdk.request.TemplateCustomFieldRequest;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.Plugin;
import io.metersphere.system.domain.ServiceIntegration;
import io.metersphere.system.domain.Template;
import io.metersphere.system.domain.TemplateExample;
import io.metersphere.system.domain.*;
import io.metersphere.system.dto.ProjectDTO;
import io.metersphere.system.dto.sdk.TemplateDTO;
import io.metersphere.system.dto.sdk.request.TemplateCustomFieldRequest;
import io.metersphere.system.mapper.CustomFieldOptionMapper;
import io.metersphere.system.service.BaseTemplateService;
import io.metersphere.system.service.PlatformPluginService;
import io.metersphere.system.service.PluginLoadService;
import io.metersphere.system.service.ServiceIntegrationService;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.pf4j.PluginWrapper;
import org.springframework.stereotype.Service;
@ -55,6 +55,9 @@ public class ProjectTemplateService extends BaseTemplateService {
@Resource
private ProjectApplicationService projectApplicationService;
@Resource
private CustomFieldOptionMapper customFieldOptionMapper;
@Override
public List list(String projectId, String scene) {
projectService.checkResourceExist(projectId);
@ -382,4 +385,41 @@ public class ProjectTemplateService extends BaseTemplateService {
templateEnableConfig.put(scene.name(), !isOrganizationTemplateEnable(project.getOrganizationId(), scene.name())));
return templateEnableConfig;
}
/**
* 获取表头可设置自定义字段接口提供
* @param projectId
* @param scene
* @return
*/
public List<CustomFieldOptions> getTableCustomsField(String projectId, String scene) {
TemplateExample example = new TemplateExample();
example.createCriteria().andScopeIdEqualTo(projectId).andSceneEqualTo(scene);
List<Template> templates = templateMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(templates)) {
List<String> templateIds = templates.stream().map(Template::getId).collect(Collectors.toList());
List<TemplateCustomField> fieldList = baseTemplateCustomFieldService.getByTemplateIds(templateIds);
List<String> fieldIds = fieldList.stream().map(TemplateCustomField::getFieldId).distinct().collect(Collectors.toList());
List<CustomField> customFields = baseCustomFieldService.getByIds(fieldIds);
CustomFieldOptionExample optionExample = new CustomFieldOptionExample();
optionExample.createCriteria().andFieldIdIn(fieldIds);
List<CustomFieldOption> customFieldOptions = customFieldOptionMapper.selectByExample(optionExample);
Map<String, List<CustomFieldOption>> optionMap = customFieldOptions.stream().collect(Collectors.groupingBy(CustomFieldOption::getFieldId));
List<CustomFieldOptions> collect = customFields.stream().map(customField -> {
CustomFieldOptions optionDTO = new CustomFieldOptions();
optionDTO.setId(customField.getId());
if (customField.getInternal()) {
customField.setName(baseCustomFieldService.translateInternalField(customField.getName()));
} else {
optionDTO.setName(customField.getName());
}
optionDTO.setOptions(optionMap.get(customField.getId()));
optionDTO.setInternal(customField.getInternal());
optionDTO.setType(customField.getType());
return optionDTO;
}).collect(Collectors.toList());
return collect;
}
return new ArrayList<>();
}
}

View File

@ -467,4 +467,13 @@ public class ProjectTemplateControllerTests extends BaseTest {
projectTemplateService.getTemplateDTOById("test_template_id", DEFAULT_PROJECT_ID, TemplateScene.FUNCTIONAL.name());
projectTemplateService.getTemplateDTOById("test_template_id_1", "test_project_id_1", TemplateScene.FUNCTIONAL.name());
}
@Test
@Order(3)
public void getCustomFields() throws Exception {
projectTemplateService.getTableCustomsField("DEFAULT_PROJECT_ID", TemplateScene.FUNCTIONAL.name());
projectTemplateService.getTableCustomsField(DEFAULT_PROJECT_ID, TemplateScene.FUNCTIONAL.name());
projectTemplateService.getTableCustomsField("test_project_id_2", TemplateScene.FUNCTIONAL.name());
}
}

View File

@ -1,2 +1,10 @@
INSERT INTO template (id, name, remark, internal, update_time, create_time, create_user, scope_type, scope_id, enable_third_part, ref_id, scene)
VALUES ('test_template_id_1', 'functional_default', '', b'1', 1696992836000, 1696992836000, 'admin', 'ORGANIZATION', 'test_project_id_1', b'0', NULL, 'FUNCTIONAL');
VALUES ('test_template_id_1', 'functional_default', '', b'1', 1696992836000, 1696992836000, 'admin', 'ORGANIZATION', 'test_project_id_1', b'0', NULL, 'FUNCTIONAL');
INSERT INTO template (id, name, remark, internal, update_time, create_time, create_user, scope_type, scope_id, enable_third_part, ref_id, scene)
VALUES ('test_template_id_2', 'functional_default', '', b'0', 1696992836000, 1696992836000, 'admin', 'ORGANIZATION', 'test_project_id_2', b'0', NULL, 'FUNCTIONAL');
INSERT INTO template_custom_field(id, field_id, template_id, required, pos, api_field_id, default_value) VALUES ('100555929702891957', '100555929702891955', 'test_template_id_2', b'1', 0, NULL, NULL);
INSERT INTO custom_field(id, name, scene, type, remark, internal, scope_type, create_time, update_time, create_user, ref_id, enable_option_key, scope_id) VALUES ('100555929702891955', '测试自定义字段', 'FUNCTIONAL', 'SELECT', '', b'0', 'ORGANIZATION', 1698810592000, 1698810592000, 'admin', NULL, b'0', '100001');