fix(接口测试): 接口测试首页-接口数量统计卡片-已覆盖、未覆盖统计增加按照请求类型的详细统计以及跳转
--bug=1020480 --user=宋天阳 【接口测试】github #20341接口测试首页-未覆盖链接无法根据协议类型准确筛选并显示,很容易造成误解 https://www.tapd.cn/55049933/s/1348871
This commit is contained in:
parent
2effdb1a0c
commit
ef8eb44bc6
|
@ -1,15 +1,19 @@
|
||||||
package io.metersphere.api.dto.datacount.response;
|
package io.metersphere.api.dto.datacount.response;
|
||||||
|
|
||||||
import io.metersphere.api.dto.datacount.ApiDataCountResult;
|
import io.metersphere.api.dto.datacount.ApiDataCountResult;
|
||||||
|
import io.metersphere.base.domain.ApiDefinition;
|
||||||
import io.metersphere.commons.constants.RequestTypeConstants;
|
import io.metersphere.commons.constants.RequestTypeConstants;
|
||||||
import io.metersphere.commons.enums.ApiHomeFilterEnum;
|
import io.metersphere.commons.enums.ApiHomeFilterEnum;
|
||||||
import io.metersphere.commons.enums.ApiReportStatus;
|
import io.metersphere.commons.enums.ApiReportStatus;
|
||||||
import io.metersphere.commons.enums.ApiTestDataStatus;
|
import io.metersphere.commons.enums.ApiTestDataStatus;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.collections.MapUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接口数据统计返回
|
* 接口数据统计返回
|
||||||
|
@ -23,6 +27,19 @@ public class ApiDataCountDTO {
|
||||||
private long rpcCount = 0;
|
private long rpcCount = 0;
|
||||||
private long sqlCount = 0;
|
private long sqlCount = 0;
|
||||||
private long createdInWeek = 0;
|
private long createdInWeek = 0;
|
||||||
|
|
||||||
|
//不同请求方式的覆盖数
|
||||||
|
private long httpCovered = 0;
|
||||||
|
private long tcpCovered = 0;
|
||||||
|
private long sqlCovered = 0;
|
||||||
|
private long rpcCovered = 0;
|
||||||
|
|
||||||
|
//不同请求方式的未覆盖
|
||||||
|
private long httpNotCovered = 0;
|
||||||
|
private long tcpNotCovered = 0;
|
||||||
|
private long rpcNotCovered = 0;
|
||||||
|
private long sqlNotCovered = 0;
|
||||||
|
|
||||||
private long coveredCount = 0;
|
private long coveredCount = 0;
|
||||||
private long notCoveredCount = 0;
|
private long notCoveredCount = 0;
|
||||||
private long runningCount = 0;
|
private long runningCount = 0;
|
||||||
|
@ -49,11 +66,29 @@ public class ApiDataCountDTO {
|
||||||
//通过率
|
//通过率
|
||||||
private String passRate = "0%";
|
private String passRate = "0%";
|
||||||
|
|
||||||
/**
|
public void countProtocol(Map<String, List<ApiDefinition>> protocalAllApiMap) {
|
||||||
* 对Protocol视角对查询结果进行统计
|
for (Map.Entry<String, List<ApiDefinition>> entry : protocalAllApiMap.entrySet()) {
|
||||||
*
|
switch (entry.getKey()) {
|
||||||
* @param countResultList 查询参数
|
case RequestTypeConstants.DUBBO:
|
||||||
*/
|
this.rpcCount += entry.getValue().size();
|
||||||
|
break;
|
||||||
|
case RequestTypeConstants.HTTP:
|
||||||
|
this.httpCount += entry.getValue().size();
|
||||||
|
break;
|
||||||
|
case RequestTypeConstants.SQL:
|
||||||
|
this.sqlCount += entry.getValue().size();
|
||||||
|
break;
|
||||||
|
case RequestTypeConstants.TCP:
|
||||||
|
this.tcpCount += entry.getValue().size();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.total = this.rpcCount + this.httpCount + this.sqlCount + this.tcpCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void countProtocol(List<ApiDataCountResult> countResultList) {
|
public void countProtocol(List<ApiDataCountResult> countResultList) {
|
||||||
for (ApiDataCountResult countResult :
|
for (ApiDataCountResult countResult :
|
||||||
countResultList) {
|
countResultList) {
|
||||||
|
@ -77,7 +112,6 @@ public class ApiDataCountDTO {
|
||||||
this.total = this.rpcCount + this.httpCount + this.sqlCount + this.tcpCount;
|
this.total = this.rpcCount + this.httpCount + this.sqlCount + this.tcpCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对Status视角对查询结果进行统计
|
* 对Status视角对查询结果进行统计
|
||||||
*
|
*
|
||||||
|
@ -162,4 +196,56 @@ public class ApiDataCountDTO {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统计覆盖率相关数据
|
||||||
|
*
|
||||||
|
* @param coverageMap 和覆盖率相关的protocol集合
|
||||||
|
* @param isUnCovered 是否统计的是未覆盖的数据
|
||||||
|
*/
|
||||||
|
public void countCovered(Map<String, List<ApiDefinition>> coverageMap, boolean isUnCovered) {
|
||||||
|
if (MapUtils.isNotEmpty(coverageMap)) {
|
||||||
|
for (Map.Entry<String, List<ApiDefinition>> entry : coverageMap.entrySet()) {
|
||||||
|
if (CollectionUtils.isNotEmpty(entry.getValue())) {
|
||||||
|
switch (entry.getKey()) {
|
||||||
|
case RequestTypeConstants.DUBBO:
|
||||||
|
if (isUnCovered) {
|
||||||
|
this.rpcNotCovered += entry.getValue().size();
|
||||||
|
} else {
|
||||||
|
this.rpcCovered += entry.getValue().size();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RequestTypeConstants.HTTP:
|
||||||
|
if (isUnCovered) {
|
||||||
|
this.httpNotCovered += entry.getValue().size();
|
||||||
|
} else {
|
||||||
|
this.httpCovered += entry.getValue().size();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RequestTypeConstants.SQL:
|
||||||
|
if (isUnCovered) {
|
||||||
|
this.sqlNotCovered += entry.getValue().size();
|
||||||
|
} else {
|
||||||
|
this.sqlCovered += entry.getValue().size();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RequestTypeConstants.TCP:
|
||||||
|
if (isUnCovered) {
|
||||||
|
this.tcpNotCovered += entry.getValue().size();
|
||||||
|
} else {
|
||||||
|
this.tcpCovered += entry.getValue().size();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isUnCovered) {
|
||||||
|
this.notCoveredCount = this.rpcNotCovered + this.httpNotCovered + this.tcpNotCovered + this.sqlNotCovered;
|
||||||
|
} else {
|
||||||
|
this.coveredCount = this.rpcCovered + this.httpCovered + this.tcpCovered + this.sqlCovered;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package io.metersphere.base.mapper.ext;
|
package io.metersphere.base.mapper.ext;
|
||||||
|
|
||||||
import io.metersphere.api.dto.datacount.ApiDataCountResult;
|
import io.metersphere.api.dto.datacount.ApiDataCountResult;
|
||||||
import io.metersphere.api.dto.definition.*;
|
import io.metersphere.api.dto.definition.ApiComputeResult;
|
||||||
|
import io.metersphere.api.dto.definition.ApiDefinitionRequest;
|
||||||
|
import io.metersphere.api.dto.definition.ApiDefinitionResult;
|
||||||
|
import io.metersphere.api.dto.definition.ApiModuleDTO;
|
||||||
import io.metersphere.base.domain.*;
|
import io.metersphere.base.domain.*;
|
||||||
import io.metersphere.dto.RelationshipGraphData;
|
import io.metersphere.dto.RelationshipGraphData;
|
||||||
import io.metersphere.request.BaseQueryRequest;
|
import io.metersphere.request.BaseQueryRequest;
|
||||||
|
@ -25,9 +28,7 @@ public interface ExtApiDefinitionMapper {
|
||||||
|
|
||||||
int reduction(@Param("ids") List<String> ids);
|
int reduction(@Param("ids") List<String> ids);
|
||||||
|
|
||||||
List<ApiDataCountResult> countProtocolByProjectID(@Param("projectId") String projectId, @Param("versionId") String versionId);
|
List<ApiDefinition> selectBaseInfoByProjectIDAndVersion(@Param("projectId") String projectId, @Param("versionId") String versionId);
|
||||||
|
|
||||||
Long countByProjectIDAndCreateInThisWeek(@Param("projectId") String projectId, @Param("versionId") String versionId, @Param("firstDayTimestamp") long firstDayTimestamp, @Param("lastDayTimestamp") long lastDayTimestamp);
|
|
||||||
|
|
||||||
List<ApiDataCountResult> countStateByProjectID(@Param("projectId") String projectId, @Param("versionId") String versionId);
|
List<ApiDataCountResult> countStateByProjectID(@Param("projectId") String projectId, @Param("versionId") String versionId);
|
||||||
|
|
||||||
|
@ -55,7 +56,7 @@ public interface ExtApiDefinitionMapper {
|
||||||
|
|
||||||
Long getLastOrder(@Param("projectId") String projectId, @Param("baseOrder") Long baseOrder);
|
Long getLastOrder(@Param("projectId") String projectId, @Param("baseOrder") Long baseOrder);
|
||||||
|
|
||||||
long countApiByProjectIdAndHasCase(@Param("projectId") String projectId, @Param("versionId") String versionId);
|
List<ApiDefinition> selectBaseInfoByProjectIdAndHasCase(@Param("projectId") String projectId, @Param("versionId") String versionId);
|
||||||
|
|
||||||
List<RelationshipGraphData.Node> getForGraph(@Param("ids") Set<String> ids);
|
List<RelationshipGraphData.Node> getForGraph(@Param("ids") Set<String> ids);
|
||||||
|
|
||||||
|
|
|
@ -396,8 +396,8 @@
|
||||||
</foreach>
|
</foreach>
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<select id="countProtocolByProjectID" resultType="io.metersphere.api.dto.datacount.ApiDataCountResult">
|
<select id="selectBaseInfoByProjectIDAndVersion" resultType="io.metersphere.base.domain.ApiDefinition">
|
||||||
SELECT protocol AS groupField, count(DISTINCT ref_id) AS countNumber
|
SELECT id,name,method,protocol,path,create_time
|
||||||
FROM api_definition
|
FROM api_definition
|
||||||
WHERE project_id = #{projectId}
|
WHERE project_id = #{projectId}
|
||||||
AND `status` != 'Trash'
|
AND `status` != 'Trash'
|
||||||
|
@ -407,7 +407,6 @@
|
||||||
<if test="versionId == null">
|
<if test="versionId == null">
|
||||||
AND latest = 1
|
AND latest = 1
|
||||||
</if>
|
</if>
|
||||||
GROUP BY protocol
|
|
||||||
</select>
|
</select>
|
||||||
<select id="countStateByProjectID" resultType="io.metersphere.api.dto.datacount.ApiDataCountResult">
|
<select id="countStateByProjectID" resultType="io.metersphere.api.dto.datacount.ApiDataCountResult">
|
||||||
SELECT status AS groupField, count(id) AS countNumber
|
SELECT status AS groupField, count(id) AS countNumber
|
||||||
|
@ -422,19 +421,7 @@
|
||||||
</if>
|
</if>
|
||||||
GROUP BY status
|
GROUP BY status
|
||||||
</select>
|
</select>
|
||||||
<select id="countByProjectIDAndCreateInThisWeek" resultType="java.lang.Long">
|
|
||||||
SELECT count(id) AS countNumber
|
|
||||||
FROM api_definition
|
|
||||||
WHERE project_id = #{projectId}
|
|
||||||
AND create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp}
|
|
||||||
AND `status` != 'Trash'
|
|
||||||
<if test="versionId != null">
|
|
||||||
AND version_id = #{versionId}
|
|
||||||
</if>
|
|
||||||
<if test="versionId == null">
|
|
||||||
AND latest = 1
|
|
||||||
</if>
|
|
||||||
</select>
|
|
||||||
<select id="countApiCoverageByProjectID" resultType="io.metersphere.api.dto.datacount.ApiDataCountResult">
|
<select id="countApiCoverageByProjectID" resultType="io.metersphere.api.dto.datacount.ApiDataCountResult">
|
||||||
SELECT count(api.id) AS countNumber,
|
SELECT count(api.id) AS countNumber,
|
||||||
if(test_case_api.api_definition_id is null, "unCovered", "covered") AS groupField
|
if(test_case_api.api_definition_id is null, "unCovered", "covered") AS groupField
|
||||||
|
@ -681,6 +668,23 @@
|
||||||
</if>
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectBaseInfoByProjectIdAndHasCase" resultType="io.metersphere.base.domain.ApiDefinition">
|
||||||
|
select id, path, method, protocol
|
||||||
|
FROM api_definition
|
||||||
|
WHERE project_id = #{projectId}
|
||||||
|
AND `status` != 'Trash'
|
||||||
|
AND
|
||||||
|
id IN (
|
||||||
|
SELECT api_definition_id FROM api_test_case WHERE `status` is null or `status` != 'Trash'
|
||||||
|
)
|
||||||
|
<if test="versionId != null">
|
||||||
|
AND version_id = #{versionId}
|
||||||
|
</if>
|
||||||
|
<if test="versionId == null">
|
||||||
|
AND latest = 1
|
||||||
|
</if>
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="selectEffectiveIdByProjectIdAndHaveNotCase" resultType="io.metersphere.base.domain.ApiDefinition">
|
<select id="selectEffectiveIdByProjectIdAndHaveNotCase" resultType="io.metersphere.base.domain.ApiDefinition">
|
||||||
select id, path, method, protocol
|
select id, path, method, protocol
|
||||||
from api_definition
|
from api_definition
|
||||||
|
@ -1008,22 +1012,6 @@
|
||||||
order by `order` desc limit 1;
|
order by `order` desc limit 1;
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="countApiByProjectIdAndHasCase" resultType="java.lang.Long">
|
|
||||||
SELECT COUNT(id)
|
|
||||||
FROM api_definition
|
|
||||||
WHERE project_id = #{projectId}
|
|
||||||
AND `status` != 'Trash'
|
|
||||||
AND
|
|
||||||
id IN (
|
|
||||||
SELECT api_definition_id FROM api_test_case WHERE `status` is null or `status` != 'Trash'
|
|
||||||
)
|
|
||||||
<if test="versionId != null">
|
|
||||||
AND version_id = #{versionId}
|
|
||||||
</if>
|
|
||||||
<if test="versionId == null">
|
|
||||||
AND latest = 1
|
|
||||||
</if>
|
|
||||||
</select>
|
|
||||||
<select id="getForGraph" resultType="io.metersphere.dto.RelationshipGraphData$Node">
|
<select id="getForGraph" resultType="io.metersphere.dto.RelationshipGraphData$Node">
|
||||||
select id,num,`name`
|
select id,num,`name`
|
||||||
from api_definition
|
from api_definition
|
||||||
|
|
|
@ -57,10 +57,12 @@ public class ApiHomeController {
|
||||||
public ApiDataCountDTO apiCount(@PathVariable String projectId, @PathVariable String versionId) {
|
public ApiDataCountDTO apiCount(@PathVariable String projectId, @PathVariable String versionId) {
|
||||||
versionId = this.initializationVersionId(versionId);
|
versionId = this.initializationVersionId(versionId);
|
||||||
ApiDataCountDTO apiCountResult = new ApiDataCountDTO();
|
ApiDataCountDTO apiCountResult = new ApiDataCountDTO();
|
||||||
List<ApiDataCountResult> countResultByProtocolList = apiDefinitionService.countProtocolByProjectID(projectId, versionId);
|
//所有有效接口,用于计算不同请求的接口数量、本周创建、覆盖率
|
||||||
apiCountResult.countProtocol(countResultByProtocolList);
|
Map<String, List<ApiDefinition>> protocolAllDefinitionMap = apiDefinitionService.countEffectiveByProjectId(projectId, versionId);
|
||||||
long dateCountByCreateInThisWeek = apiDefinitionService.countByProjectIDAndCreateInThisWeek(projectId, versionId);
|
apiCountResult.countProtocol(protocolAllDefinitionMap);
|
||||||
apiCountResult.setCreatedInWeek(dateCountByCreateInThisWeek);
|
//本周创建
|
||||||
|
apiCountResult.setCreatedInWeek(apiDefinitionService.getApiByCreateInThisWeek(protocolAllDefinitionMap).size());
|
||||||
|
|
||||||
//查询完成率、进行中、已完成
|
//查询完成率、进行中、已完成
|
||||||
List<ApiDataCountResult> countResultByStateList = apiDefinitionService.countStateByProjectID(projectId, versionId);
|
List<ApiDataCountResult> countResultByStateList = apiDefinitionService.countStateByProjectID(projectId, versionId);
|
||||||
apiCountResult.countStatus(countResultByStateList);
|
apiCountResult.countStatus(countResultByStateList);
|
||||||
|
@ -70,29 +72,33 @@ public class ApiHomeController {
|
||||||
DecimalFormat df = new DecimalFormat("0.0");
|
DecimalFormat df = new DecimalFormat("0.0");
|
||||||
apiCountResult.setCompletedRate(df.format(completeRateNumber) + "%");
|
apiCountResult.setCompletedRate(df.format(completeRateNumber) + "%");
|
||||||
}
|
}
|
||||||
//统计覆盖率
|
|
||||||
long effectiveApiCount = apiDefinitionService.countEffectiveByProjectId(projectId, versionId);
|
|
||||||
long apiHasCase = apiDefinitionService.countApiByProjectIdAndHasCase(projectId, versionId);
|
|
||||||
List<ApiDefinition> apiNoCaseList = apiDefinitionService.selectEffectiveIdByProjectIdAndHaveNotCase(projectId, versionId);
|
|
||||||
Map<String, Map<String, String>> scenarioUrlList = apiAutomationService.selectScenarioUseUrlByProjectId(projectId, null);
|
|
||||||
int apiInScenario = apiAutomationService.getApiIdInScenario(projectId, scenarioUrlList, apiNoCaseList).size();
|
|
||||||
|
|
||||||
if (effectiveApiCount == 0) {
|
if (apiCountResult.getTotal() == 0) {
|
||||||
|
//没有任何接口数据
|
||||||
apiCountResult.setCoveredCount(0);
|
apiCountResult.setCoveredCount(0);
|
||||||
apiCountResult.setNotCoveredCount(0);
|
apiCountResult.setNotCoveredCount(0);
|
||||||
} else {
|
} else {
|
||||||
long quotedApiCount = apiHasCase + apiInScenario;
|
|
||||||
apiCountResult.setCoveredCount(quotedApiCount);
|
//统计覆盖率. 覆盖:接口下挂有用例/接口路径被场景引用
|
||||||
apiCountResult.setNotCoveredCount(effectiveApiCount - quotedApiCount);
|
//带有用例的接口
|
||||||
|
List<ApiDefinition> apiDefinitionHasCase = apiDefinitionService.selectBaseInfoByProjectIdAndHasCase(projectId, versionId);
|
||||||
|
//没有case的接口
|
||||||
|
List<ApiDefinition> apiNoCaseList = apiDefinitionService.getAPiNotInCollection(protocolAllDefinitionMap, apiDefinitionHasCase);
|
||||||
|
Map<String, Map<String, String>> scenarioUrlList = apiAutomationService.selectScenarioUseUrlByProjectId(projectId, null);
|
||||||
|
List<String> apiIdInScenario = apiAutomationService.getApiIdInScenario(projectId, scenarioUrlList, apiNoCaseList);
|
||||||
|
|
||||||
|
Map<String, List<ApiDefinition>> unCoverageApiMap = apiDefinitionService.getUnCoverageApiMap(apiNoCaseList, apiIdInScenario);
|
||||||
|
Map<String, List<ApiDefinition>> coverageApiMap = apiDefinitionService.filterMap(protocolAllDefinitionMap, unCoverageApiMap);
|
||||||
|
apiCountResult.countCovered(coverageApiMap, false);
|
||||||
|
apiCountResult.countCovered(unCoverageApiMap, true);
|
||||||
try {
|
try {
|
||||||
float coveredRateNumber = (float) quotedApiCount * 100 / effectiveApiCount;
|
float coveredRateNumber = (float) apiCountResult.getCoveredCount() * 100 / apiCountResult.getTotal();
|
||||||
DecimalFormat df = new DecimalFormat("0.0");
|
DecimalFormat df = new DecimalFormat("0.0");
|
||||||
apiCountResult.setApiCoveredRate(df.format(coveredRateNumber) + "%");
|
apiCountResult.setApiCoveredRate(df.format(coveredRateNumber) + "%");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtil.error("转化通过率失败:[" + quotedApiCount + "," + effectiveApiCount + "]", e);
|
LogUtil.error("转化通过率失败:[" + apiCountResult.getCoveredCount() + "," + apiCountResult.getTotal() + "]", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return apiCountResult;
|
return apiCountResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1164,32 +1164,29 @@ public class ApiDefinitionService {
|
||||||
apiTestCaseService.relevanceByApiByReview(request);
|
apiTestCaseService.relevanceByApiByReview(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据统计-接口类型
|
|
||||||
*
|
|
||||||
* @param projectId 项目ID
|
|
||||||
* @return List
|
|
||||||
*/
|
|
||||||
public List<ApiDataCountResult> countProtocolByProjectID(String projectId, String versionId) {
|
|
||||||
return extApiDefinitionMapper.countProtocolByProjectID(projectId, versionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 统计本周创建的数据总量
|
* 统计本周创建的数据总量
|
||||||
*
|
*
|
||||||
* @param projectId
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public long countByProjectIDAndCreateInThisWeek(String projectId, String versionId) {
|
public List<ApiDefinition> getApiByCreateInThisWeek(Map<String, List<ApiDefinition>> protocalAllApiList) {
|
||||||
Map<String, Date> startAndEndDateInWeek = DateUtils.getWeedFirstTimeAndLastTime(new Date());
|
Map<String, Date> startAndEndDateInWeek = DateUtils.getWeedFirstTimeAndLastTime(new Date());
|
||||||
|
|
||||||
Date firstTime = startAndEndDateInWeek.get("firstTime");
|
Date firstTime = startAndEndDateInWeek.get("firstTime");
|
||||||
Date lastTime = startAndEndDateInWeek.get("lastTime");
|
Date lastTime = startAndEndDateInWeek.get("lastTime");
|
||||||
|
|
||||||
if (firstTime == null || lastTime == null) {
|
if (firstTime == null || lastTime == null) {
|
||||||
return 0;
|
return new ArrayList<>();
|
||||||
} else {
|
} else {
|
||||||
return extApiDefinitionMapper.countByProjectIDAndCreateInThisWeek(projectId, versionId, firstTime.getTime(), lastTime.getTime());
|
List<ApiDefinition> apiCreatedInWeekList = new ArrayList<>();
|
||||||
|
for (List<ApiDefinition> apiList : protocalAllApiList.values()) {
|
||||||
|
for (ApiDefinition api : apiList) {
|
||||||
|
if (api.getCreateTime() >= firstTime.getTime() && api.getCreateTime() <= lastTime.getTime()) {
|
||||||
|
apiCreatedInWeekList.add(api);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return apiCreatedInWeekList;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1668,24 +1665,17 @@ public class ApiDefinitionService {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public long countEffectiveByProjectId(String projectId, String versionId) {
|
public Map<String, List<ApiDefinition>> countEffectiveByProjectId(String projectId, String versionId) {
|
||||||
if (StringUtils.isEmpty(projectId)) {
|
if (StringUtils.isEmpty(projectId)) {
|
||||||
return 0;
|
return new HashMap<>();
|
||||||
} else {
|
} else {
|
||||||
ApiDefinitionExample example = new ApiDefinitionExample();
|
List<ApiDefinition> apiDefinitionList = extApiDefinitionMapper.selectBaseInfoByProjectIDAndVersion(projectId, versionId);
|
||||||
ApiDefinitionExample.Criteria criteria = example.createCriteria();
|
return apiDefinitionList.stream().collect(Collectors.groupingBy(ApiDefinition::getProtocol));
|
||||||
criteria.andProjectIdEqualTo(projectId).andStatusNotEqualTo("Trash");
|
|
||||||
if (StringUtils.isNotBlank(versionId)) {
|
|
||||||
criteria.andVersionIdEqualTo(versionId);
|
|
||||||
} else {
|
|
||||||
criteria.andLatestEqualTo(true);
|
|
||||||
}
|
|
||||||
return apiDefinitionMapper.countByExample(example);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long countApiByProjectIdAndHasCase(String projectId, String versionId) {
|
public List<ApiDefinition> selectBaseInfoByProjectIdAndHasCase(String projectId, String versionId) {
|
||||||
return extApiDefinitionMapper.countApiByProjectIdAndHasCase(projectId, versionId);
|
return extApiDefinitionMapper.selectBaseInfoByProjectIdAndHasCase(projectId, versionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRelationshipCount(String id) {
|
public int getRelationshipCount(String id) {
|
||||||
|
@ -2401,4 +2391,61 @@ public class ApiDefinitionService {
|
||||||
updateCaseList.forEach(apiTestCaseBatchMapper::updateByPrimaryKeyWithBLOBs);
|
updateCaseList.forEach(apiTestCaseBatchMapper::updateByPrimaryKeyWithBLOBs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ApiDefinition> getAPiNotInCollection(Map<String, List<ApiDefinition>> protocolAllDefinitionMap, List<ApiDefinition> checkCollection) {
|
||||||
|
List<ApiDefinition> returnList = new ArrayList<>();
|
||||||
|
if (MapUtils.isEmpty(protocolAllDefinitionMap)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
List<String> idInCheckCollection = new ArrayList<>();
|
||||||
|
if (CollectionUtils.isNotEmpty(checkCollection)) {
|
||||||
|
idInCheckCollection = checkCollection.stream().map(ApiDefinition::getId).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
for (List<ApiDefinition> apiList : protocolAllDefinitionMap.values()) {
|
||||||
|
for (ApiDefinition api : apiList) {
|
||||||
|
if (!idInCheckCollection.contains(api.getId())) {
|
||||||
|
returnList.add(api);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, List<ApiDefinition>> getUnCoverageApiMap(List<ApiDefinition> apiNoCaseList, List<String> apiIdInScenario) {
|
||||||
|
Map<String, List<ApiDefinition>> returnMap = new HashMap<>();
|
||||||
|
if (CollectionUtils.isNotEmpty(apiNoCaseList)) {
|
||||||
|
if (apiIdInScenario == null) {
|
||||||
|
apiIdInScenario = new ArrayList<>();
|
||||||
|
}
|
||||||
|
for (ApiDefinition api : apiNoCaseList) {
|
||||||
|
if (!apiIdInScenario.contains(api.getId())) {
|
||||||
|
if (returnMap.containsKey(api.getProtocol())) {
|
||||||
|
returnMap.get(api.getProtocol()).add(api);
|
||||||
|
} else {
|
||||||
|
returnMap.put(api.getProtocol(), new ArrayList<>() {{
|
||||||
|
this.add(api);
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, List<ApiDefinition>> filterMap(Map<String, List<ApiDefinition>> targetMap, Map<String, List<ApiDefinition>> filter) {
|
||||||
|
Map<String, List<ApiDefinition>> returnMap = new HashMap<>();
|
||||||
|
if (MapUtils.isNotEmpty(targetMap)) {
|
||||||
|
for (Map.Entry<String, List<ApiDefinition>> entry : targetMap.entrySet()) {
|
||||||
|
List<ApiDefinition> filterList = filter.get(entry.getKey());
|
||||||
|
List<ApiDefinition> resultList = null;
|
||||||
|
if (CollectionUtils.isNotEmpty(filterList)) {
|
||||||
|
resultList = new ArrayList<>(CollectionUtils.subtract(entry.getValue(), filterList));
|
||||||
|
} else {
|
||||||
|
resultList = entry.getValue();
|
||||||
|
}
|
||||||
|
returnMap.put(entry.getKey(), resultList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnMap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,10 @@
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<api-dashboard @redirectPage="redirectPage" ref="apiDashboard" />
|
<api-dashboard
|
||||||
|
@redirectPage="redirectPage"
|
||||||
|
@redirectPageWithDataType="redirectPageWithDataType"
|
||||||
|
ref="apiDashboard" />
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<api-case-dashboard @redirectPage="redirectPage" ref="apiCaseDashboard" />
|
<api-case-dashboard @redirectPage="redirectPage" ref="apiCaseDashboard" />
|
||||||
|
@ -130,6 +133,7 @@ export default {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param redirectPage 要跳转的页面
|
* @param redirectPage 要跳转的页面
|
||||||
|
@ -189,6 +193,34 @@ export default {
|
||||||
window.open(home.href, '_blank');
|
window.open(home.href, '_blank');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
redirectPageWithDataType(redirectPage, dataType, selectRange, selectParam, type) {
|
||||||
|
let uuid = getUUID();
|
||||||
|
let home;
|
||||||
|
let selectVersionId = this.versionId;
|
||||||
|
if (!selectVersionId || selectVersionId === '') {
|
||||||
|
selectVersionId = 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (redirectPage) {
|
||||||
|
case 'api':
|
||||||
|
home = this.$router.resolve({
|
||||||
|
name: 'ApiDefinitionWithQuery',
|
||||||
|
params: {
|
||||||
|
versionId: selectVersionId,
|
||||||
|
redirectID: uuid,
|
||||||
|
dataType: dataType,
|
||||||
|
dataSelectRange: selectRange,
|
||||||
|
projectId: this.projectId,
|
||||||
|
type: type,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (home) {
|
||||||
|
window.open(home.href, '_blank');
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -38,12 +38,87 @@
|
||||||
{{ $t('home.dashboard.public.covered') }}
|
{{ $t('home.dashboard.public.covered') }}
|
||||||
</span>
|
</span>
|
||||||
<div class="common-amount">
|
<div class="common-amount">
|
||||||
|
<el-popover placement="top-start" width="200" trigger="hover">
|
||||||
|
<div>
|
||||||
|
<el-row class="addition-info-title">
|
||||||
|
<el-col>
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background-color: #aa4fbf;
|
||||||
|
margin: 7px;
|
||||||
|
float: left;
|
||||||
|
" />
|
||||||
|
<span style="line-height: 22px">HTTP:</span>
|
||||||
|
<div style="float: right">
|
||||||
<el-link
|
<el-link
|
||||||
class="addition-info-num"
|
class="coverage-num-link"
|
||||||
v-permission-disable="['PROJECT_API_DEFINITION:READ']"
|
@click="redirectPageWithDataType('api', 'api', 'covered', null, 'HTTP')"
|
||||||
@click="redirectPage('api', 'api', 'covered', null)">
|
>{{ apiData.httpCovered }}</el-link
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row class="addition-info-title">
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background-color: #fad355;
|
||||||
|
margin: 7px;
|
||||||
|
float: left;
|
||||||
|
" />
|
||||||
|
<span style="line-height: 22px">RPC :</span>
|
||||||
|
<div style="float: right">
|
||||||
|
<el-link
|
||||||
|
class="coverage-num-link"
|
||||||
|
@click="redirectPageWithDataType('api', 'api', 'covered', null, 'DUBBO')"
|
||||||
|
>{{ apiData.rpcCovered }}</el-link
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
<el-row class="addition-info-title">
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background-color: #14e1c6;
|
||||||
|
margin: 7px;
|
||||||
|
float: left;
|
||||||
|
" />
|
||||||
|
<span style="line-height: 22px">TCP :</span>
|
||||||
|
<div style="float: right">
|
||||||
|
<el-link
|
||||||
|
class="coverage-num-link"
|
||||||
|
@click="redirectPageWithDataType('api', 'api', 'covered', null, 'TCP')"
|
||||||
|
>{{ apiData.tcpCovered }}
|
||||||
|
</el-link>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
<el-row class="addition-info-title">
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background-color: #4e83fd;
|
||||||
|
margin: 7px;
|
||||||
|
float: left;
|
||||||
|
" />
|
||||||
|
<span style="line-height: 22px">SQL :</span>
|
||||||
|
<div style="float: right">
|
||||||
|
<el-link
|
||||||
|
class="coverage-num-link"
|
||||||
|
@click="redirectPageWithDataType('api', 'api', 'covered', null, 'SQL')"
|
||||||
|
>{{ apiData.sqlCovered }}</el-link
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
<el-link slot="reference" class="addition-info-num">
|
||||||
{{ formatAmount(apiData.coveredCount) }}
|
{{ formatAmount(apiData.coveredCount) }}
|
||||||
</el-link>
|
</el-link>
|
||||||
|
</el-popover>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
|
@ -51,12 +126,85 @@
|
||||||
{{ $t('home.dashboard.public.not_covered') }}
|
{{ $t('home.dashboard.public.not_covered') }}
|
||||||
</span>
|
</span>
|
||||||
<div class="common-amount">
|
<div class="common-amount">
|
||||||
|
<el-popover placement="top-start" width="200" trigger="hover">
|
||||||
|
<div>
|
||||||
|
<el-row class="addition-info-title">
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background-color: #aa4fbf;
|
||||||
|
margin: 7px;
|
||||||
|
float: left;
|
||||||
|
" />
|
||||||
|
<span style="line-height: 22px">HTTP:</span>
|
||||||
|
<div style="float: right">
|
||||||
<el-link
|
<el-link
|
||||||
class="addition-info-num"
|
class="coverage-num-link"
|
||||||
v-permission-disable="['PROJECT_API_DEFINITION:READ']"
|
@click="redirectPageWithDataType('api', 'api', 'notCovered', null, 'HTTP')"
|
||||||
@click="redirectPage('api', 'api', 'notCovered', null)">
|
>{{ apiData.httpNotCovered }}</el-link
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
<el-row class="addition-info-title">
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background-color: #fad355;
|
||||||
|
margin: 7px;
|
||||||
|
float: left;
|
||||||
|
" />
|
||||||
|
<span style="line-height: 22px">RPC :</span>
|
||||||
|
<div style="float: right">
|
||||||
|
<el-link
|
||||||
|
class="coverage-num-link"
|
||||||
|
@click="redirectPageWithDataType('api', 'api', 'notCovered', null, 'DUBBO')"
|
||||||
|
>{{ apiData.rpcNotCovered }}</el-link
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
<el-row class="addition-info-title">
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background-color: #14e1c6;
|
||||||
|
margin: 7px;
|
||||||
|
float: left;
|
||||||
|
" />
|
||||||
|
<span style="line-height: 22px">TCP :</span>
|
||||||
|
<div style="float: right">
|
||||||
|
<el-link
|
||||||
|
class="coverage-num-link"
|
||||||
|
@click="redirectPageWithDataType('api', 'api', 'notCovered', null, 'TCP')"
|
||||||
|
>{{ apiData.tcpNotCovered }}</el-link
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
<el-row class="addition-info-title">
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background-color: #4e83fd;
|
||||||
|
margin: 7px;
|
||||||
|
float: left;
|
||||||
|
" />
|
||||||
|
<span style="line-height: 22px">SQL :</span>
|
||||||
|
<div style="float: right">
|
||||||
|
<el-link
|
||||||
|
class="coverage-num-link"
|
||||||
|
@click="redirectPageWithDataType('api', 'api', 'notCovered', null, 'SQL')"
|
||||||
|
>{{ apiData.sqlNotCovered }}</el-link
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
<el-link slot="reference" class="addition-info-num">
|
||||||
{{ formatAmount(apiData.notCoveredCount) }}
|
{{ formatAmount(apiData.notCoveredCount) }}
|
||||||
</el-link>
|
</el-link>
|
||||||
|
</el-popover>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
@ -155,6 +303,14 @@ export default {
|
||||||
runningCount: 0,
|
runningCount: 0,
|
||||||
finishedCount: 0,
|
finishedCount: 0,
|
||||||
notRunCount: 0,
|
notRunCount: 0,
|
||||||
|
httpCovered: 0,
|
||||||
|
rpcCovered: 0,
|
||||||
|
tcpCovered: 0,
|
||||||
|
sqlCovered: 0,
|
||||||
|
httpNotCovered: 0,
|
||||||
|
rpcNotCovered: 0,
|
||||||
|
tcpNotCovered: 0,
|
||||||
|
sqlNotCovered: 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -183,8 +339,18 @@ export default {
|
||||||
redirectPage(redirectPage, dataType, selectRange, selectParam) {
|
redirectPage(redirectPage, dataType, selectRange, selectParam) {
|
||||||
this.$emit('redirectPage', redirectPage, dataType, selectRange, selectParam);
|
this.$emit('redirectPage', redirectPage, dataType, selectRange, selectParam);
|
||||||
},
|
},
|
||||||
|
redirectPageWithDataType(redirectPage, dataType, selectRange, selectParam, type) {
|
||||||
|
this.$emit('redirectPageWithDataType', redirectPage, dataType, selectRange, selectParam, type);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped>
|
||||||
|
.coverage-num-link {
|
||||||
|
line-height: 22px;
|
||||||
|
color: #783887 !important;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue