feat(测试跟踪): 测试跟踪首页交互升级

--story=1010425 --user=宋昌昌 【测试跟踪】测试跟踪首页交互升级 https://www.tapd.cn/55049933/s/1296114
This commit is contained in:
song-cc-rock 2022-11-15 16:25:14 +08:00 committed by 刘瑞斌
parent e7fe6e5d4e
commit 206354aeee
38 changed files with 2450 additions and 771 deletions

View File

@ -28,7 +28,8 @@ public interface ExtApiDefinitionExecResultMapper {
long countByTestCaseIDInProject(String projectId); long countByTestCaseIDInProject(String projectId);
List<ExecutedCaseInfoResult> findFailureCaseInTestPlanByProjectIDAndExecuteTimeAndLimitNumber(@Param("projectId") String projectId, @Param("selectFunctionCase") boolean selectFunctionCase, @Param("startTimestamp") long startTimestamp); List<ExecutedCaseInfoResult> findFailureCaseInTestPlanByProjectIDAndExecuteTimeAndLimitNumber(@Param("projectId") String projectId, @Param("selectFunctionCase") boolean selectFunctionCase,
@Param("startTimestamp") long startTimestamp, @Param("limitNumber") int limitNumber);
String selectExecResult(String resourceId); String selectExecResult(String resourceId);

View File

@ -61,6 +61,7 @@
<select id="findFailureCaseInTestPlanByProjectIDAndExecuteTimeAndLimitNumber" <select id="findFailureCaseInTestPlanByProjectIDAndExecuteTimeAndLimitNumber"
resultType="io.metersphere.api.dto.datacount.ExecutedCaseInfoResult"> resultType="io.metersphere.api.dto.datacount.ExecutedCaseInfoResult">
SELECT * FROM (
SELECT * SELECT *
FROM ( FROM (
SELECT testCase.testPlanCaseID AS testPlanCaseID, SELECT testCase.testPlanCaseID AS testPlanCaseID,
@ -147,7 +148,8 @@
testCase.id testCase.id
</if> </if>
) showTable ) showTable
ORDER BY showTable.failureTimes DESC ORDER BY showTable.failureTimes DESC LIMIT ${limitNumber}
) pageTable
</select> </select>
<select id="selectExecResult" resultType="java.lang.String"> <select id="selectExecResult" resultType="java.lang.String">
select ader.status select ader.status

View File

@ -1,12 +1,16 @@
package io.metersphere.controller.home; package io.metersphere.controller.home;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.DubboProvider; import io.metersphere.api.dto.DubboProvider;
import io.metersphere.api.dto.JmxInfoDTO; import io.metersphere.api.dto.JmxInfoDTO;
import io.metersphere.api.dto.RegistryCenter; import io.metersphere.api.dto.RegistryCenter;
import io.metersphere.api.dto.datacount.ApiDataCountResult; import io.metersphere.api.dto.datacount.ApiDataCountResult;
import io.metersphere.api.dto.datacount.ExecutedCaseInfoResult;
import io.metersphere.api.dto.datacount.response.ApiDataCountDTO; import io.metersphere.api.dto.datacount.response.ApiDataCountDTO;
import io.metersphere.api.dto.datacount.response.CoveredDTO; import io.metersphere.api.dto.datacount.response.CoveredDTO;
import io.metersphere.api.dto.datacount.response.ExecuteResultCountDTO; import io.metersphere.api.dto.datacount.response.ExecuteResultCountDTO;
import io.metersphere.api.dto.datacount.response.ExecutedCaseInfoDTO;
import io.metersphere.api.dto.definition.RunDefinitionRequest; import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.dto.export.ScenarioToPerformanceInfoDTO; import io.metersphere.api.dto.export.ScenarioToPerformanceInfoDTO;
import io.metersphere.base.domain.ApiDefinition; import io.metersphere.base.domain.ApiDefinition;
@ -15,6 +19,8 @@ import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.commons.enums.ExecutionExecuteTypeEnum; import io.metersphere.commons.enums.ExecutionExecuteTypeEnum;
import io.metersphere.commons.utils.DataFormattingUtil; import io.metersphere.commons.utils.DataFormattingUtil;
import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.service.BaseScheduleService; import io.metersphere.service.BaseScheduleService;
import io.metersphere.service.definition.ApiDefinitionExecResultService; import io.metersphere.service.definition.ApiDefinitionExecResultService;
import io.metersphere.service.definition.ApiDefinitionService; import io.metersphere.service.definition.ApiDefinitionService;
@ -26,6 +32,7 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -223,4 +230,28 @@ public class ApiHomeController {
returnDTO.setProjectEnvMap(projectEnvMap); returnDTO.setProjectEnvMap(projectEnvMap);
return returnDTO; return returnDTO;
} }
@GetMapping("/failure/case/about/plan/{projectId}/{selectFunctionCase}/{limitNumber}/{goPage}/{pageSize}")
public Pager<List<ExecutedCaseInfoDTO>> failureCaseAboutTestPlan(@PathVariable String projectId, @PathVariable boolean selectFunctionCase,
@PathVariable int limitNumber, @PathVariable int goPage, @PathVariable int pageSize) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
List<ExecutedCaseInfoResult> selectDataList = apiDefinitionExecResultService.findFailureCaseInfoByProjectIDAndLimitNumberInSevenDays(projectId, selectFunctionCase, limitNumber);
List<ExecutedCaseInfoDTO> returnList = new ArrayList<>(selectDataList.size());
for (int dataIndex = 0; dataIndex < selectDataList.size(); dataIndex++) {
ExecutedCaseInfoDTO dataDTO = new ExecutedCaseInfoDTO();
dataDTO.setSortIndex(dataIndex + 1);
ExecutedCaseInfoResult selectData = selectDataList.get(dataIndex);
dataDTO.setCaseID(selectData.getTestCaseID());
dataDTO.setCaseName(selectData.getCaseName());
dataDTO.setTestPlan(selectData.getTestPlan());
dataDTO.setFailureTimes(selectData.getFailureTimes());
dataDTO.setTestPlanId(selectData.getTestPlanId());
dataDTO.setCaseType(selectData.getCaseType());
dataDTO.setId(selectData.getId());
dataDTO.setTestPlanDTOList(selectData.getTestPlanDTOList());
returnList.add(dataDTO);
}
return PageUtils.setPageInfo(page, returnList);
}
} }

View File

@ -373,7 +373,7 @@ public class ApiDefinitionExecResultService {
if (startTime == null) { if (startTime == null) {
return new ArrayList<>(0); return new ArrayList<>(0);
} else { } else {
List<ExecutedCaseInfoResult> list = extApiDefinitionExecResultMapper.findFailureCaseInTestPlanByProjectIDAndExecuteTimeAndLimitNumber(projectId, selectFunctionCase, startTime.getTime()); List<ExecutedCaseInfoResult> list = extApiDefinitionExecResultMapper.findFailureCaseInTestPlanByProjectIDAndExecuteTimeAndLimitNumber(projectId, selectFunctionCase, startTime.getTime(), limitNumber);
List<ExecutedCaseInfoResult> returnList = new ArrayList<>(limitNumber); List<ExecutedCaseInfoResult> returnList = new ArrayList<>(limitNumber);

View File

@ -1,6 +1,9 @@
package io.metersphere.task.controller; package io.metersphere.task.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.commons.utils.CronUtils; import io.metersphere.commons.utils.CronUtils;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.Pager;
import io.metersphere.dto.TaskInfoResult; import io.metersphere.dto.TaskInfoResult;
import io.metersphere.request.BaseQueryRequest; import io.metersphere.request.BaseQueryRequest;
@ -44,8 +47,10 @@ public class TaskController {
return taskService.getRunningTasks(request); return taskService.getRunningTasks(request);
} }
@PostMapping("/runningTask/{projectID}") @PostMapping("/runningTask/{projectID}/{goPage}/{pageSize}")
public List<TaskInfoResult> runningTask(@PathVariable String projectID, @RequestBody BaseQueryRequest request) { public Pager<List<TaskInfoResult> >runningTask(@PathVariable String projectID, @PathVariable int goPage, @PathVariable int pageSize,
@RequestBody BaseQueryRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
List<TaskInfoResult> resultList = taskService.findRunningTaskInfoByProjectID(projectID, request); List<TaskInfoResult> resultList = taskService.findRunningTaskInfoByProjectID(projectID, request);
int dataIndex = 1; int dataIndex = 1;
for (TaskInfoResult taskInfo : for (TaskInfoResult taskInfo :
@ -56,7 +61,7 @@ public class TaskController {
taskInfo.setNextExecutionTime(nextExecutionTime.getTime()); taskInfo.setNextExecutionTime(nextExecutionTime.getTime());
} }
} }
return resultList; return PageUtils.setPageInfo(page, resultList);
} }
@PostMapping(value = "/stop/batch") @PostMapping(value = "/stop/batch")

View File

@ -6,4 +6,5 @@ package io.metersphere.constants;
*/ */
public class SystemCustomField { public class SystemCustomField {
public static final String ISSUE_STATUS = "状态"; public static final String ISSUE_STATUS = "状态";
public static final String ISSUE_DEGREE = "严重程度";
} }

View File

@ -139,9 +139,11 @@ public class TestCaseReviewController {
testCaseReviewService.editTestReviewStatus(reviewId); testCaseReviewService.editTestReviewStatus(reviewId);
} }
@PostMapping("/list/all/relate") @PostMapping("/list/all/relate/{goPage}/{pageSize}")
public List<TestReviewDTOWithMetric> listRelateAll(@RequestBody ReviewRelateRequest request) { public Pager<List<TestReviewDTOWithMetric>> listRelateAll(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ReviewRelateRequest request) {
return testCaseReviewService.listRelateAll(request); testCaseReviewService.setReviewIds(request);
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, testCaseReviewService.listRelateAll(request));
} }
@PostMapping("/edit/follows") @PostMapping("/edit/follows")

View File

@ -47,6 +47,13 @@ public class TrackController {
statistics.setReviewRage(df.format(reviewed) + "%"); statistics.setReviewRage(df.format(reviewed) + "%");
} }
long reviewedTotal = statistics.getPassCount() + statistics.getUnPassCount();
if (reviewedTotal != 0) {
float reviewPass = (float) statistics.getPassCount() * 100 / (statistics.getPassCount() + statistics.getUnPassCount());
DecimalFormat df = new DecimalFormat("0.0");
statistics.setReviewPassRage(df.format(reviewPass) + "%");
}
statistics.setP0CountStr("P0&nbsp;&nbsp;<br/><br/>" + statistics.getP0CaseCountNumber()); statistics.setP0CountStr("P0&nbsp;&nbsp;<br/><br/>" + statistics.getP0CaseCountNumber());
statistics.setP1CountStr("P1&nbsp;&nbsp;<br/><br/>" + statistics.getP1CaseCountNumber()); statistics.setP1CountStr("P1&nbsp;&nbsp;<br/><br/>" + statistics.getP1CaseCountNumber());
statistics.setP2CountStr("P2&nbsp;&nbsp;<br/><br/>" + statistics.getP2CaseCountNumber()); statistics.setP2CountStr("P2&nbsp;&nbsp;<br/><br/>" + statistics.getP2CaseCountNumber());

View File

@ -10,7 +10,14 @@ import java.util.List;
@Setter @Setter
public class BugStatistics { public class BugStatistics {
private long bugTotalSize; private long bugUnclosedCount;
private String rage; private long bugTotalCount;
private long caseTotalCount;
private long unClosedP0Size;
private long unClosedP1Size;
private long unClosedP2Size;
private long unClosedP3Size;
private String unClosedRage;
private String bugCaseRage;
private List<TestPlanBugCount> list = new ArrayList<>(); private List<TestPlanBugCount> list = new ArrayList<>();
} }

View File

@ -90,6 +90,10 @@ public class TrackStatisticsDTO {
* 评审率 * 评审率
*/ */
private String reviewRage = " 0%"; private String reviewRage = " 0%";
/**
* 评审通过率
*/
private String reviewPassRage = " 0%";
/** /**
* 未评审 * 未评审
*/ */

View File

@ -3,10 +3,13 @@ package io.metersphere.request.testreview;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.util.List;
@Getter @Getter
@Setter @Setter
public class ReviewRelateRequest { public class ReviewRelateRequest {
private String type; private String type;
private String projectId; private String projectId;
private String workspaceId; private String workspaceId;
private List<String> reviewIds;
} }

View File

@ -121,4 +121,16 @@ public class CustomFieldIssuesService extends CustomFieldResourceService {
Map<String, String> statusMap = customFieldIssues.stream().collect(Collectors.toMap(CustomFieldIssues::getResourceId, CustomFieldIssues::getValue)); Map<String, String> statusMap = customFieldIssues.stream().collect(Collectors.toMap(CustomFieldIssues::getResourceId, CustomFieldIssues::getValue));
return statusMap; return statusMap;
} }
public Map<String, String> getIssueDegreeMap(List<String> issueIds, String projectId) {
if (CollectionUtils.isEmpty(issueIds)) {
return new HashMap<>(0);
}
CustomField customField = baseCustomFieldService.getCustomFieldByName(projectId, SystemCustomField.ISSUE_DEGREE);
CustomFieldIssuesExample example = new CustomFieldIssuesExample();
example.createCriteria().andFieldIdEqualTo(customField.getId()).andResourceIdIn(issueIds);
List<CustomFieldIssues> customFieldIssues = customFieldIssuesMapper.selectByExample(example);
Map<String, String> statusMap = customFieldIssues.stream().collect(Collectors.toMap(CustomFieldIssues::getResourceId, CustomFieldIssues::getValue));
return statusMap;
}
} }

View File

@ -440,7 +440,7 @@ public class TestCaseReviewService {
request.setWorkspaceId(workspaceId); request.setWorkspaceId(workspaceId);
request.setProjectId(projectId); request.setProjectId(projectId);
request.setReviewIds(extTestReviewCaseMapper.findRelateTestReviewId(user.getId(), workspaceId, projectId)); request.setReviewIds(relateRequest.getReviewIds());
List<TestReviewDTOWithMetric> testReviews = extTestCaseReviewMapper.listRelate(request); List<TestReviewDTOWithMetric> testReviews = extTestCaseReviewMapper.listRelate(request);
@ -477,6 +477,10 @@ public class TestCaseReviewService {
return testReviews; return testReviews;
} }
public void setReviewIds(ReviewRelateRequest request) {
request.setReviewIds(extTestReviewCaseMapper.findRelateTestReviewId(SessionUtils.getUserId(), request.getWorkspaceId(), request.getProjectId()));
}
private String getReviewName(List<String> userIds, String projectId) { private String getReviewName(List<String> userIds, String projectId) {
QueryMemberRequest queryMemberRequest = new QueryMemberRequest(); QueryMemberRequest queryMemberRequest = new QueryMemberRequest();
queryMemberRequest.setProjectId(projectId); queryMemberRequest.setProjectId(projectId);

View File

@ -118,10 +118,19 @@ public class TrackService {
int index = 1; int index = 1;
int totalUnClosedPlanBugSize = 0; int totalUnClosedPlanBugSize = 0;
int totalPlanBugSize = 0; int totalPlanBugSize = 0;
int totalCaseSize = 0;
int unClosedP0Size = 0;
int unClosedP1Size = 0;
int unClosedP2Size = 0;
int unClosedP3Size = 0;
for (TestPlan plan : plans) { for (TestPlan plan : plans) {
Map<String, Integer> bugSizeMap = getPlanBugSize(plan.getId(), projectId); Map<String, Integer> bugSizeMap = getPlanBugSize(plan.getId(), projectId);
int planBugSize = bugSizeMap.get("total"); int planBugSize = bugSizeMap.get("total");
int unClosedPlanBugSize = bugSizeMap.get("unClosed"); int unClosedPlanBugSize = bugSizeMap.get("unClosed");
unClosedP0Size += bugSizeMap.get("p0Size");
unClosedP1Size += bugSizeMap.get("p1Size");
unClosedP2Size += bugSizeMap.get("p2Size");
unClosedP3Size += bugSizeMap.get("p3Size");
totalUnClosedPlanBugSize += unClosedPlanBugSize; totalUnClosedPlanBugSize += unClosedPlanBugSize;
totalPlanBugSize += planBugSize; totalPlanBugSize += planBugSize;
// bug为0不记录 // bug为0不记录
@ -137,6 +146,7 @@ public class TrackService {
testPlanBug.setPlanId(plan.getId()); testPlanBug.setPlanId(plan.getId());
int planCaseSize = getPlanCaseSize(plan.getId()); int planCaseSize = getPlanCaseSize(plan.getId());
totalCaseSize += planCaseSize;
testPlanBug.setCaseSize(planCaseSize); testPlanBug.setCaseSize(planCaseSize);
testPlanBug.setBugSize(unClosedPlanBugSize); testPlanBug.setBugSize(unClosedPlanBugSize);
@ -146,10 +156,20 @@ public class TrackService {
} }
bugStatistics.setList(list); bugStatistics.setList(list);
bugStatistics.setBugUnclosedCount(totalUnClosedPlanBugSize);
bugStatistics.setBugTotalCount(totalPlanBugSize);
bugStatistics.setCaseTotalCount(totalCaseSize);
float rage = totalPlanBugSize == 0 ? 0 : (float) totalUnClosedPlanBugSize * 100 / totalPlanBugSize; float rage = totalPlanBugSize == 0 ? 0 : (float) totalUnClosedPlanBugSize * 100 / totalPlanBugSize;
DecimalFormat df = new DecimalFormat("0.0"); DecimalFormat df = new DecimalFormat("0.0");
bugStatistics.setRage(df.format(rage) + "%"); bugStatistics.setUnClosedRage(df.format(rage) + "%");
bugStatistics.setBugTotalSize(totalUnClosedPlanBugSize);
float caseRange = totalCaseSize == 0 ? 0 : (float) totalUnClosedPlanBugSize * 100 / totalCaseSize;
bugStatistics.setBugCaseRage(df.format(caseRange) + "%");
bugStatistics.setUnClosedP0Size(unClosedP0Size);
bugStatistics.setUnClosedP1Size(unClosedP1Size);
bugStatistics.setUnClosedP2Size(unClosedP2Size);
bugStatistics.setUnClosedP3Size(unClosedP3Size);
return bugStatistics; return bugStatistics;
} }
@ -162,20 +182,51 @@ public class TrackService {
List<String> issueIds = extTestCaseMapper.getTestPlanBug(planId); List<String> issueIds = extTestCaseMapper.getTestPlanBug(planId);
Map<String, String> statusMap = customFieldIssuesService.getIssueStatusMap(issueIds, projectId); Map<String, String> statusMap = customFieldIssuesService.getIssueStatusMap(issueIds, projectId);
Map<String, String> degreeMap = customFieldIssuesService.getIssueDegreeMap(issueIds, projectId);
Map<String, Integer> bugSizeMap = new HashMap<>(); Map<String, Integer> bugSizeMap = new HashMap<>();
bugSizeMap.put("total", issueIds.size()); bugSizeMap.put("total", issueIds.size());
// 缺陷是否有状态 // 缺陷是否有状态
List<String> unClosedIds = new ArrayList<>();
if (MapUtils.isEmpty(statusMap)) { if (MapUtils.isEmpty(statusMap)) {
unClosedIds = issueIds;
bugSizeMap.put("unClosed", issueIds.size()); bugSizeMap.put("unClosed", issueIds.size());
return bugSizeMap; } else {
unClosedIds = issueIds.stream()
.filter(id -> !StringUtils.equals(statusMap.getOrDefault(id, StringUtils.EMPTY).replaceAll("\"", StringUtils.EMPTY), "closed"))
.collect(Collectors.toList());
bugSizeMap.put("unClosed", unClosedIds.size());
} }
int unClosedSize = (int) issueIds.stream() // 如果没有严重程度字段
.filter(id -> !StringUtils.equals(statusMap.getOrDefault(id, StringUtils.EMPTY).replaceAll("\"", StringUtils.EMPTY), "closed")) int p0Size = 0;
.count(); int p1Size = 0;
bugSizeMap.put("unClosed", unClosedSize); int p2Size = 0;
int p3Size = 0;
if (MapUtils.isEmpty(degreeMap)) {
bugSizeMap.put("p0Size", unClosedIds.size());
} else {
for (String unClosedId : unClosedIds) {
String degree = degreeMap.getOrDefault(unClosedId, StringUtils.EMPTY).replaceAll("\"", StringUtils.EMPTY);
if (StringUtils.equalsIgnoreCase(degree, "P0")) {
p0Size += 1;
} else if (StringUtils.equalsIgnoreCase(degree, "P1")) {
p1Size += 1;
} else if (StringUtils.equalsIgnoreCase(degree, "P2")) {
p2Size += 1;
} else if (StringUtils.equalsIgnoreCase(degree, "P3")) {
p3Size += 1;
} else {
p0Size += 1;
}
}
}
bugSizeMap.put("p0Size", p0Size);
bugSizeMap.put("p1Size", p1Size);
bugSizeMap.put("p2Size", p2Size);
bugSizeMap.put("p3Size", p3Size);
return bugSizeMap; return bugSizeMap;
} }

View File

@ -2,6 +2,6 @@ import {post, get} from "@/business/utils/sdk-utils";
const BASE_URL = '/home/'; const BASE_URL = '/home/';
export function homeTestPlanFailureCaseGet(projectId, selectFunctionCase, limitNumber) { export function homeTestPlanFailureCaseGet(projectId, selectFunctionCase, limitNumber, currentPage, pageSize) {
return get(BASE_URL + `failure/case/about/plan/${projectId}/${selectFunctionCase}/${limitNumber}`); return get(BASE_URL + `failure/case/about/plan/${projectId}/${selectFunctionCase}/${limitNumber}/${currentPage}/${pageSize}`);
} }

View File

@ -3,8 +3,8 @@ import {buildPagePath} from "@/api/base-network";
const BASE_URL = '/test/case/review/'; const BASE_URL = '/test/case/review/';
export function getRelateTestCaseReview(param) { export function getRelateTestCaseReview(currentPage, pageSize, param) {
return post(BASE_URL + 'list/all/relate', param); return post(BASE_URL + 'list/all/relate/' + currentPage + "/" + pageSize, param);
} }
export function testReviewApiCaseList(page, param) { export function testReviewApiCaseList(page, param) {

View File

@ -12,11 +12,23 @@ export function getTrackCaseBar(selectProjectId) {
return get("/track/case/bar/" + selectProjectId); return get("/track/case/bar/" + selectProjectId);
} }
export function getTrackRunningTask(selectProjectId, param) { export function getTrackRunningTask(selectProjectId, currentPage, pageSize, param) {
return post("/task/center/runningTask/" + selectProjectId, param); return post("/task/center/runningTask/" + selectProjectId + "/" + currentPage + "/" + pageSize, param);
} }
export function getTrackBugCount(selectProjectId) { export function getTrackBugCount(selectProjectId) {
return get("/track/bug/count/" + selectProjectId); return get("/track/bug/count/" + selectProjectId);
} }
export function formatNumber(param) {
let num = (param || 0).toString(), result = '';
while (num.length > 3) {
result = ',' + num.slice(-3) + result;
num = num.slice(0, num.length - 3);
}
if (num) {
result = num + result;
}
return result;
}

View File

@ -715,7 +715,10 @@ export default {
break; break;
case 'notReviewed': case 'notReviewed':
this.condition.filters.review_status = ['Prepare']; this.condition.filters.review_status = ['Prepare'];
break; break
case 'reviewed':
this.condition.filters.review_status = ['UnPass', 'Pass'];
break
case 'reviewSuccess': case 'reviewSuccess':
this.condition.filters.review_status = ['Pass']; this.condition.filters.review_status = ['Pass'];
break; break;

View File

@ -1,45 +1,47 @@
<template> <template>
<div style="background-color:#F5F6F7">
<ms-container> <ms-container>
<ms-main-container v-loading="result.loading"> <ms-main-container style="overflow-y: hidden">
<el-row :gutter="5"> <div class="track-home-layout">
<el-col :span="6"> <el-row :gutter="16">
<div class="square"> <el-col :span="12">
<case-count-card :track-count-data="trackCountData" class="track-card" @redirectPage="redirectPage"/> <case-count-card @redirectPage="redirectPage"/>
</div>
</el-col>
<el-col :span="6">
<div class="square">
<relevance-case-card :relevance-count-data="relevanceCountData" class="track-card"
@redirectPage="redirectPage"/>
</div>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<div class="square"> <relevance-case-card @redirectPage="redirectPage"/>
<case-maintenance :case-option="caseOption" class="track-card"/>
</div>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="5"> <el-row :gutter="16" style="margin-top: 16px">
<el-col :span="12"> <el-col :span="12">
<bug-count-card class="track-card"/> <bug-count-card />
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<ms-failure-test-case-list class="track-card" :select-function-case="true" @redirectPage="redirectPage"/> <case-maintenance />
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="5"> <el-row style="margin-top: 16px">
<el-col :span="12"> <el-col style="background-color: #FFFFFF;">
<review-list class="track-card"/> <ms-failure-test-case-list :select-function-case="true" @redirectPage="redirectPage"/>
</el-col>
<el-col :span="12">
<ms-running-task-list :call-from="'track_home'" class="track-card" @redirectPage="redirectPage"/>
</el-col> </el-col>
</el-row> </el-row>
<el-row style="margin-top: 16px">
<el-col style="background-color: #FFFFFF;">
<review-list/>
</el-col>
</el-row>
<el-row style="margin-top: 16px">
<el-col style="background-color: #FFFFFF;">
<ms-running-task-list :call-from="'track_home'" @redirectPage="redirectPage"/>
</el-col>
</el-row>
</div>
</ms-main-container> </ms-main-container>
</ms-container> </ms-container>
</div>
</template> </template>
<script> <script>
@ -49,15 +51,12 @@ import MsContainer from "metersphere-frontend/src/components/MsContainer";
import CaseCountCard from "./components/CaseCountCard"; import CaseCountCard from "./components/CaseCountCard";
import RelevanceCaseCard from "./components/RelevanceCaseCard"; import RelevanceCaseCard from "./components/RelevanceCaseCard";
import CaseMaintenance from "./components/CaseMaintenance"; import CaseMaintenance from "./components/CaseMaintenance";
import {COUNT_NUMBER, COUNT_NUMBER_SHALLOW} from "metersphere-frontend/src/utils/constants";
import BugCountCard from "./components/BugCountCard"; import BugCountCard from "./components/BugCountCard";
import ReviewList from "./components/ReviewList"; import ReviewList from "./components/ReviewList";
import MsRunningTaskList from "./components/RunningTaskList"; import MsRunningTaskList from "./components/RunningTaskList";
import {getUUID} from "metersphere-frontend/src/utils"; import {getUUID} from "metersphere-frontend/src/utils";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token"; import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import MsFailureTestCaseList from "@/business/home/components/FailureTestCaseList"; import MsFailureTestCaseList from "@/business/home/components/FailureTestCaseList";
import {getTrackCaseBar, getTrackCount, getTrackRelevanceCount} from "@/api/track";
import {useStore} from "@/store";
require('echarts/lib/component/legend'); require('echarts/lib/component/legend');
export default { export default {
@ -75,97 +74,14 @@ export default {
}, },
data() { data() {
return { return {
result: {},
trackCountData: {},
relevanceCountData: {},
caseOption: {},
} }
}, },
activated() {
this.init();
},
computed: { computed: {
projectId() { projectId() {
return getCurrentProjectID(); return getCurrentProjectID();
}, },
}, },
methods: { methods: {
init() {
let selectProjectId = this.projectId;
if (!selectProjectId) {
return;
}
getTrackCount(selectProjectId)
.then(r => {
this.trackCountData = r.data;
});
getTrackRelevanceCount(selectProjectId)
.then(r => {
this.relevanceCountData = r.data;
});
getTrackCaseBar(selectProjectId)
.then(r => {
let data = r.data;
this.setBarOption(data);
});
},
setBarOption(data) {
let xAxis = [];
data.map(d => {
if (!xAxis.includes(d.xAxis)) {
xAxis.push(d.xAxis);
}
});
let yAxis1 = data.filter(d => d.groupName === 'FUNCTIONCASE').map(d => [d.xAxis, d.yAxis]);
let yAxis2 = data.filter(d => d.groupName === 'RELEVANCECASE').map(d => [d.xAxis, d.yAxis]);
let store = useStore();
let option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
xAxis: {
type: 'category',
data: xAxis
},
yAxis: {
type: 'value',
axisLine: {
show: false
},
axisTick: {
show: false
}
},
legend: {
data: [this.$t('test_track.home.function_case_count'), this.$t('test_track.home.relevance_case_count')],
orient: 'vertical',
right: '80',
},
series: [
{
name: this.$t('test_track.home.function_case_count'),
data: yAxis1,
type: 'bar',
barWidth: 50,
itemStyle: {
color: store.theme ? store.theme : COUNT_NUMBER
}
},
{
name: this.$t('test_track.home.relevance_case_count'),
data: yAxis2,
type: 'bar',
barWidth: 50,
color: store.theme ? store.theme : COUNT_NUMBER_SHALLOW
}]
};
this.caseOption = option;
},
redirectPage(page, dataType, selectType, title) { redirectPage(page, dataType, selectType, title) {
//api //api
//UUID //UUID
@ -196,21 +112,84 @@ export default {
</script> </script>
<style scoped> <style scoped>
.square { :deep(.el-card__header) {
border: 0px;
padding: 24px;
}
:deep(.el-card__body) {
border: 0px;
padding: 0px;
margin: 0px 24px 24px 24px;
}
.track-home-layout {
margin: 12px 24px;
min-width: 1100px;
}
.track-home-layout :deep(.dashboard-title) {
font-size: 18px;
font-weight: 500;
}
.track-home-layout :deep(.common-amount) {
margin-top: 4px;
}
.track-home-layout :deep(.dashboard-card) {
height: 392px;
}
.track-home-layout :deep(.main-info) {
height: 197px;
}
.track-home-layout :deep(.main-info-card) {
height: 197px;
width: 100%; width: 100%;
height: 400px; color: #646A73;
background-color: #FFFFFF;
box-sizing: border-box;
border: 1px solid #DEE0E3;
border-radius: 4px;
} }
.rectangle { .track-home-layout :deep(.addition-info) {
width: 100%; height: 86px;
height: 400px; margin: 16px 0px 0px 0px;
} }
.el-row { .track-home-layout :deep(.addition-info-title) {
margin-bottom: 5px; line-height: 22px;
font-size: 14px;
font-weight: 400;
color: #646A73;
} }
.track-card { .track-home-layout :deep(.addition-info-text) {
height: 100%; line-height: 28px;
color: #783887;
font-size: 20px;
font-weight: 500;
}
.track-home-layout :deep(.addition-info-num) {
line-height: 22px;
color: #783887;
font-size: 14px;
font-weight: 500;
}
.track-home-layout :deep(.home-table-cell) {
height: 38px;
background-color: #F5F6F7;
font-size: 14px;
font-weight: 500;
border: 1px solid rgba(31, 35, 41, 0.15);
border-right-width: 0;
border-left-width: 0;
color: #1F2329;
line-height: 22px;
} }
</style> </style>

View File

@ -1,114 +1,195 @@
<template> <template>
<el-card class="table-card" v-loading="result.loading" body-style="padding:10px;"> <el-card class="table-card" shadow="never" body-style="padding:10px 5px;">
<div slot="header"> <div slot="header">
<span class="title"> <span class="title">
{{ $t('test_track.home.bug_count') }} {{ $t('test_track.home.bug_count') }}
</span> </span>
</div> </div>
<el-container>
<el-aside width="120px">
<count-rectangle-chart :content="bugTotalSize"/>
<div>
{{ $t('test_track.home.percentage') }}
<span class="rage">
{{ rage }}
</span>
</div>
</el-aside>
<el-table border :data="tableData" class="adjust-table table-content" height="300"> <div v-loading="loading" element-loading-background="#FFFFFF">
<el-table-column prop="index" :label="$t('test_track.home.serial_number')" <div v-show="loadError"
width="60" show-overflow-tooltip/> style="width: 100%; height: 300px; display: flex; flex-direction: column; justify-content: center;align-items: center">
<el-table-column prop="planName" :label="$t('test_track.home.test_plan_name')" <img style="height: 100px;width: 100px;"
width="130" show-overflow-tooltip> src="/assets/figma/icon_load_error.svg"/>
<template v-slot:default="scope"> <span class="addition-info-title" style="color: #646A73">{{ $t("home.dashboard.public.load_error") }}</span>
<el-link type="info" @click="goPlan(scope.row.planId)"> </div>
{{ scope.row.planName }} <div v-show="!loadError">
</el-link> <div class="main-info">
</template> <bug-count-chart :bug-data="bugData" ref="countChart" @redirectPage="redirectPage"/>
</el-table-column> </div>
<el-table-column prop="createTime" :label="$t('commons.create_time')" width="160" show-overflow-tooltip> <div class="addition-info">
<template v-slot:default="scope"> <el-row :gutter="16" style="margin: 0">
<span>{{ scope.row.createTime | datetimeFormat }}</span> <el-col :span="12" style="padding-left: 0">
</template> <hover-card
</el-table-column> :title="$t('home.bug_dashboard.un_closed_range')"
<el-table-column :main-info="bugData.unClosedRage"
prop="status" :tool-tip="unClosedBugRangeToolTip"
column-key="status" >
:label="$t('test_track.plan.plan_status')" <!--遗留缺陷所有缺陷-->
show-overflow-tooltip> <template v-slot:mouseOut>
<template v-slot:default="scope"> <div style="margin:16px 0px 0px 16px">
<span @click.stop="clickt = 'stop'"> <el-row>
<plan-status-table-item :value="scope.row.status"/> <el-col :span="12">
<span class="addition-info-title">
{{ $t('home.bug_dashboard.un_closed_count') }}
</span> </span>
<div class="common-amount">
<el-link class="addition-info-num">
{{ formatAmount(bugData.bugUnclosedCount) }}
</el-link>
</div>
</el-col>
<el-col :span="12">
<span class="addition-info-title">
{{ $t('home.bug_dashboard.total_count') }}
</span>
<div class="common-amount">
<el-link class="addition-info-num">
{{ formatAmount(bugData.bugTotalCount) }}
</el-link>
</div>
</el-col>
</el-row>
</div>
</template> </template>
</el-table-column> </hover-card>
<el-table-column prop="caseSize" :label="$t('test_track.home.case_size')" </el-col>
show-overflow-tooltip/>
<el-table-column prop="bugSize" :label="$t('test_track.home.bug_size')" <el-col :span="12" style="padding-left: 0">
show-overflow-tooltip/> <hover-card
<el-table-column prop="passRage" :label="$t('test_track.home.passing_rate')" :title="$t('home.bug_dashboard.un_closed_bug_case_range')"
show-overflow-tooltip/> :main-info="bugData.bugCaseRage"
</el-table> :tool-tip="unClosedBugCaseRangeToolTip"
</el-container> >
<!--遗留缺陷所有缺陷-->
<template v-slot:mouseOut>
<div style="margin:16px 0px 0px 16px">
<el-row>
<el-col :span="12">
<span class="addition-info-title">
{{ $t('home.bug_dashboard.un_closed_count') }}
</span>
<div class="common-amount">
<el-link class="addition-info-num">
{{ formatAmount(bugData.bugUnclosedCount) }}
</el-link>
</div>
</el-col>
<el-col :span="12">
<span class="addition-info-title">
{{ $t('home.bug_dashboard.case_count') }}
</span>
<div class="common-amount">
<el-link class="addition-info-num">
{{ formatAmount(bugData.caseTotalCount) }}
</el-link>
</div>
</el-col>
</el-row>
</div>
</template>
</hover-card>
</el-col>
</el-row>
</div>
</div>
</div>
</el-card> </el-card>
</template> </template>
<script> <script>
import bugCountChart from "@/business/home/components/chart/BugCountChart";
import hoverCard from "@/business/home/components/card/HoverCard";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token"; import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import PlanStatusTableItem from "../../common/tableItems/plan/PlanStatusTableItem";
import CountRectangleChart from "metersphere-frontend/src/components/chart/CountRectangleChart";
import {getTrackBugCount} from "@/api/track"; import {getTrackBugCount} from "@/api/track";
import {formatNumber} from "@/api/track"
export default { export default {
name: "BugCountCard", name: "BugCountCard",
components: { components: {bugCountChart, hoverCard},
CountRectangleChart,
PlanStatusTableItem
},
data() { data() {
return { return {
tableData: [], loading: false,
result: {}, loadError: false,
bugTotalSize: 0, unClosedBugRangeToolTip: this.$t('home.bug_dashboard.un_closed_range_tips'),
rage: '0%' unClosedBugCaseRangeToolTip: this.$t('home.bug_dashboard.un_closed_bug_case_range_tips'),
} bugData: {
bugCaseRage:" 0%",
bugTotalCount: 0,
bugUnclosedCount: 0,
caseTotalCount: 0,
unClosedRage:" 0%",
unClosedP0Size: 0,
unClosedP1Size: 0,
unClosedP2Size: 0,
unClosedP3Size: 0,
}, },
methods: {
init() {
getTrackBugCount(getCurrentProjectID())
.then((res) => {
let data = res.data;
this.tableData = data.list;
this.bugTotalSize = data.bugTotalSize;
this.rage = data.rage;
});
},
goPlan(id) {
if (!id) {
return;
} }
this.$router.push('/track/plan/view/' + id);
}
},
created() {
this.init()
}, },
activated() { activated() {
this.init() this.search();
},
methods: {
search() {
this.loading = true;
this.loadError = false;
let selectProjectId = getCurrentProjectID();
getTrackBugCount(selectProjectId)
.then(r => {
this.loading = false;
this.loadError = false;
this.bugData = r.data;
}).catch(() => {
this.loading = false;
this.loadError = true;
this.$refs.countChart.reload();
})
},
formatAmount(number) {
return formatNumber(number);
},
redirectPage(clickType) {
this.$emit("redirectPage", "testCase", "relationCase", clickType);
}
} }
} }
</script> </script>
<style scoped> <style scoped>
.detail-container {
margin-top: 30px;
}
.default-property {
font-size: 14px
}
.main-property {
color: #F39021;
font-size: 14px
}
.el-card :deep( .el-card__header ) { .el-card :deep( .el-card__header ) {
border-bottom: 0px solid #EBEEF5; border-bottom: 0px solid #EBEEF5;
} }
.rage { .count-info-div {
margin: 3px;
}
.count-info-div :deep( p ) {
font-size: 10px;
}
.info-tool-tip {
position: absolute;
top: 0;
}
.rows-count-number {
font-family: 'ArialMT', 'Arial', sans-serif; font-family: 'ArialMT', 'Arial', sans-serif;
font-size: 18px; font-size: 14px;
color: var(--count_number); color: var(--count_number) !important;
} }
</style> </style>

View File

@ -1,128 +1,166 @@
<template> <template>
<el-card class="table-card" v-loading="result.loading" body-style="padding:10px 5px;"> <el-card class="table-card" shadow="never" body-style="padding: 10px 5px;">
<div slot="header"> <div slot="header">
<span class="title"> <span class="title">
{{ $t('test_track.home.case_count') }} {{ $t('test_track.home.case_count') }}
</span> </span>
</div> </div>
<!--数值统计-->
<el-container> <div v-loading="loading" element-loading-background="#FFFFFF">
<el-aside width="120px"> <div v-show="loadError"
<count-rectangle-chart :content="trackCountData.allCaseCountNumber"/> style="width: 100%; height: 300px; display: flex; flex-direction: column; justify-content: center;align-items: center">
</el-aside> <img style="height: 100px;width: 100px;"
<el-main style="padding-left: 0px;padding-right: 0px;display: block"> src="/assets/figma/icon_load_error.svg"/>
<div style="width:200px;float:right;margin:0;overflow: auto"> <span class="addition-info-title" style="color: #646A73">{{ $t("home.dashboard.public.load_error") }}</span>
<el-row align="right"> </div>
<el-col :span="6" <div v-show="!loadError">
style="border-right-style: solid;border-right-width: 1px;border-right-color: #ECEEF4;"> <div class="main-info">
<div class="count-info-div" v-html="trackCountData.p0CountStr"></div> <case-count-chart :track-data="trackData" ref="countChart" @redirectPage="redirectPage"/>
</div>
<div class="addition-info">
<el-row :gutter="16" style="margin: 0">
<el-col :span="12" style="padding-left: 0">
<hover-card
:title="$t('home.rate.case_review')"
:main-info="trackData.reviewRage"
:tool-tip="caseReviewRangeToolTip"
>
<!--未评审已评审-->
<template v-slot:mouseOut>
<div style="margin:16px 0px 0px 16px">
<el-row>
<el-col :span="12">
<span class="addition-info-title">
{{ $t('home.case_review_dashboard.not_review') }}
</span>
<div class="common-amount">
<el-link class="addition-info-num" @click="redirectPage('notReviewed')">
{{ formatAmount(trackData.prepareCount) }}
</el-link>
</div>
</el-col> </el-col>
<el-col :span="6" <el-col :span="12">
style="border-right-style: solid;border-right-width: 1px;border-right-color: #ECEEF4;"> <span class="addition-info-title">
<div class="count-info-div" v-html="trackCountData.p1CountStr"></div> {{ $t('home.case_review_dashboard.finished_review') }}
</el-col> </span>
<el-col :span="6" <div class="common-amount">
style="border-right-style: solid;border-right-width: 1px;border-right-color: #ECEEF4;"> <el-link class="addition-info-num" @click="redirectPage('reviewed')">
<div class="count-info-div" v-html="trackCountData.p2CountStr"></div> {{ formatAmount(trackData.passCount + trackData.unPassCount) }}
</el-col> </el-link>
<el-col :span="6" style=""> </div>
<div class="count-info-div" v-html="trackCountData.p3CountStr"></div>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
</el-main> </template>
</el-container> </hover-card>
<!-- 本周新增-->
<el-container class="detail-container">
<el-header style="height:20px;padding: 0px;margin-bottom: 0px;font-size: 14px">
<el-row>
<el-col>
{{ $t('api_test.home_page.api_details_card.this_week_add') }}
<el-link type="info" @click="redirectPage('thisWeekCount')" target="_blank" style="color: #000000">
{{ trackCountData.thisWeekAddedCount }}
</el-link>
{{ $t('api_test.home_page.unit_of_measurement') }}
</el-col> </el-col>
</el-row>
</el-header>
<el-main style="padding:0px">
<el-row>
<el-col :span="8">&nbsp;</el-col>
</el-row>
</el-main>
</el-container>
<!-- 评审通过率 --> <el-col :span="12" style="padding-right:0">
<el-container class="detail-container"> <hover-card
<el-header style="height:20px;padding: 0px;margin-bottom: 5px;font-size: 14px"> :title="$t('home.rate.case_review_pass')"
<el-row> :main-info="trackData.reviewPassRage"
<span style="float: left"> :tool-tip="caseFinishedReviewPassRageToolTip"
{{ $t('test_track.home.review_rate') + ":" }}&nbsp;&nbsp; >
</span> <!--未通过, 已通过-->
<span style="font-size: 14px"> <template v-slot:mouseOut>
<b>{{ trackCountData.reviewRage }}</b> <div style="margin:16px 0px 0px 16px">
<el-tooltip placement="top" class="info-tool-tip">
<div slot="content">{{ $t('api_test.home_page.formula.review') }}</div>
<el-button icon="el-icon-info" style="padding:0px;border: 0px"></el-button>
</el-tooltip>
</span>
</el-row>
</el-header>
<el-main style="padding:0px">
<el-row> <el-row>
<el-col :span="8"> <el-col :span="8">
<span class="default-property"> <span class="addition-info-title">
{{ $t('test_track.review.prepare') }} {{ $t("home.case_review_dashboard.not_pass") }}
<el-link class="rows-count-number" @click="redirectPage('notReviewed')" target="_blank">
<b>
{{ trackCountData.prepareCount }}
</b>
</el-link>
</span> </span>
</el-col> <div class="common-amount">
<el-col :span="8" class="itemIsCenter"> <el-link class="addition-info-num" @click="redirectPage('UnPass')">
<span class="default-property"> {{ formatAmount(trackData.unPassCount) }}
{{ $t('test_track.review.un_pass') }}
<el-link class="rows-count-number" @click="redirectPage('reviewFail')" target="_blank">
<b>
{{ trackCountData.unPassCount }}
</b>
</el-link> </el-link>
</span> </div>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<span class="main-property" style="float: right"> <span class="addition-info-title">
{{ $t('test_track.review.pass') }} {{ $t("home.case_review_dashboard.pass") }}
<el-link class="rows-count-number" @click="redirectPage('reviewSuccess')" target="_blank">
<b>
{{ trackCountData.passCount }}
</b>
</el-link>
</span> </span>
<div class="common-amount">
<el-link class="addition-info-num" @click="redirectPage('Pass')">
{{ formatAmount(trackData.passCount) }}
</el-link>
</div>
</el-col> </el-col>
</el-row> </el-row>
</el-main> </div>
</el-container> </template>
</hover-card>
</el-col>
</el-row>
</div>
</div>
</div>
</el-card> </el-card>
</template> </template>
<script> <script>
import MsInstructionsIcon from "metersphere-frontend/src/components/MsInstructionsIcon"; import caseCountChart from "@/business/home/components/chart/CaseCountChart";
import CountRectangleChart from "metersphere-frontend/src/components/chart/CountRectangleChart"; import hoverCard from "@/business/home/components/card/HoverCard";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import {getTrackCount} from "@/api/track";
import {formatNumber} from "@/api/track"
export default { export default {
name: "CaseCountCard", name: "CaseCountCard",
components: {CountRectangleChart, MsInstructionsIcon}, components: {caseCountChart, hoverCard},
props: {
trackCountData: {},
},
data() { data() {
return { return {
result: {} loading: false,
loadError: false,
caseReviewRangeToolTip: this.$t('api_test.home_page.formula.review'),
caseFinishedReviewPassRageToolTip: this.$t('home.dashboard.case_finished_review_pass_tip'),
trackData: {
allCaseCountNumber: 0,
allRelevanceCaseCount: 0,
apiCaseCount: 0,
apiCaseCountStr: "",
coverageCount: 0,
coverageRage: "0%",
p0CaseCountNumber: 0,
p1CaseCountNumber: 0,
p2CaseCountNumber: 0,
p3CaseCountNumber: 0,
passCount: 0,
performanceCaseCount: 0,
performanceCaseCountStr: "",
prepareCount: 0,
reviewRage: " 0%",
reviewPassRage: " 0%",
scenarioCaseCount: 0,
scenarioCaseStr: "",
thisWeekAddedCount: 0,
unPassCount: 0,
uncoverageCount: 0
},
} }
}, },
activated() {
this.search();
},
methods: { methods: {
search() {
this.loading = true;
this.loadError = false;
let selectProjectId = getCurrentProjectID();
getTrackCount(selectProjectId)
.then(r => {
this.loading = false;
this.loadError = false;
this.trackData = r.data;
this.$refs.countChart.reload();
}).catch(() => {
this.loading = false;
this.loadError = true;
this.$refs.countChart.reload();
});
},
formatAmount(number) {
return formatNumber(number);
},
redirectPage(clickType) { redirectPage(clickType) {
this.$emit("redirectPage", "testCase", "case", clickType); this.$emit("redirectPage", "testCase", "case", clickType);
} }
@ -131,57 +169,4 @@ export default {
</script> </script>
<style scoped> <style scoped>
.el-aside {
line-height: 100px;
text-align: center;
}
.rows-count-number {
font-family: 'ArialMT', 'Arial', sans-serif;
font-size: 14px;
color: var(--count_number) !important;
}
.detail-container {
margin-top: 30px;
}
.default-property {
font-size: 14px;
}
.main-property {
color: #F39021;
font-size: 14px
}
.el-card :deep( .el-card__header ) {
border-bottom: 0px solid #EBEEF5;
}
.count-info-div {
margin: 3px;
}
.count-info-div :deep( p ) {
font-size: 10px;
}
.info-tool-tip {
position: absolute;
top: 0;
}
.rows-count-number {
font-family: 'ArialMT', 'Arial', sans-serif;
font-size: 14px;
color: var(--count_number) !important;
}
.itemIsCenter {
display: flex;
justify-content: center; /*主轴上居中*/
align-items: center; /*侧轴上居中*/
}
</style> </style>

View File

@ -1,29 +1,118 @@
<template> <template>
<el-card class="table-card" v-loading="result.loading" body-style="padding:10px;"> <el-card class="table-card" shadow="never" body-style="padding:10px;">
<div slot="header"> <div slot="header">
<span class="title"> <span class="title">
{{ $t('test_track.home.case_maintenance') }} {{ $t('test_track.home.case_maintenance') }}
</span> </span>
</div> </div>
<div v-loading="loading" element-loading-background="#FFFFFF">
<div v-show="loadError"
style="width: 100%; height: 300px; display: flex; flex-direction: column; justify-content: center;align-items: center">
<img style="height: 100px;width: 100px;"
src="/assets/figma/icon_load_error.svg"/>
<span class="addition-info-title" style="color: #646A73">{{ $t("home.dashboard.public.load_error") }}</span>
</div>
<div v-show="!loadError">
<el-container> <el-container>
<ms-chart ref="chart1" :options="caseOption" :autoresize="true" style="width: 100%;height: 340px"></ms-chart> <ms-chart ref="chart1" :options="caseOption" :autoresize="true" style="width: 100%;height: 323px"></ms-chart>
</el-container> </el-container>
</div>
</div>
</el-card> </el-card>
</template> </template>
<script> <script>
import MsChart from "metersphere-frontend/src/components/chart/MsChart"; import MsChart from "metersphere-frontend/src/components/chart/MsChart";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import {getTrackCaseBar} from "@/api/track";
import {useStore} from "@/store";
export default { export default {
name: "CaseMaintenance", name: "CaseMaintenance",
components: {MsChart}, components: {MsChart},
props: {
caseOption: {}
},
data() { data() {
return { return {
result: {} loading: false,
loadError: false,
caseOption: {}
} }
},
activated() {
this.search();
},
methods: {
search() {
this.loading = true;
this.loadError = false;
let selectProjectId = getCurrentProjectID();
getTrackCaseBar(selectProjectId)
.then(r => {
this.loading = false;
this.loadError = false;
let data = r.data;
this.setBarOption(data);
}).catch(() => {
this.loading = false;
this.loadError = true;
});
},
setBarOption(data) {
let xAxis = [];
data.map(d => {
if (!xAxis.includes(d.xAxis)) {
xAxis.push(d.xAxis);
}
});
let yAxis1 = data.filter(d => d.groupName === 'FUNCTIONCASE').map(d => [d.xAxis, d.yAxis]);
let yAxis2 = data.filter(d => d.groupName === 'RELEVANCECASE').map(d => [d.xAxis, d.yAxis]);
let store = useStore();
let option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
xAxis: {
type: 'category',
data: xAxis
},
yAxis: {
type: 'value',
axisLine: {
show: false
},
axisTick: {
show: false
}
},
legend: {
data: [this.$t('test_track.home.function_case_count'), this.$t('test_track.home.relevance_case_count')],
orient: 'vertical',
right: '80',
},
series: [
{
name: this.$t('test_track.home.function_case_count'),
data: yAxis1,
type: 'bar',
barWidth: 16,
itemStyle: {
color: '#783887'
}
},
{
name: this.$t('test_track.home.relevance_case_count'),
data: yAxis2,
type: 'bar',
barWidth: 16,
color: '#F9CB2E'
}]
};
this.caseOption = option;
},
} }
} }
</script> </script>

View File

@ -1,15 +1,22 @@
<template> <template>
<el-card class="table-card" v-loading="loading" body-style="padding:10px;"> <el-card class="table-card" shadow="never" v-loading="loading" body-style="padding:10px;">
<template v-slot:header> <template v-slot:header>
<span class="title"> <span class="table-title">
{{ $t('api_test.home_page.failed_case_list.title') }} {{ $t('api_test.home_page.failed_case_list.title') }}
</span> </span>
</template> </template>
<el-table border :data="tableData" class="adjust-table table-content" height="300px"> <div v-loading="loading" element-loading-background="#FFFFFF">
<el-table-column prop="sortIndex" :label="$t('home.case.index')" <div v-show="loadError"
width="100" show-overflow-tooltip/> style="width: 100%; height: 300px; display: flex; flex-direction: column; justify-content: center;align-items: center">
<el-table-column prop="caseName" :label="$t('home.case.case_name')" <img style="height: 100px;width: 100px;"
width="150"> src="/assets/figma/icon_load_error.svg"/>
<span class="addition-info-title" style="color: #646A73">{{ $t("home.dashboard.public.load_error") }}</span>
</div>
<div v-show="!loadError">
<el-table :data="tableData" class="adjust-table table-content"
:header-cell-style="{backgroundColor: '#F5F6F7'}" height="224px">
<el-table-column prop="sortIndex" :label="$t('home.case.index')" fixed show-overflow-tooltip/>
<el-table-column prop="caseName" :label="$t('home.case.case_name')" fixed>
<template v-slot:default="{row}"> <template v-slot:default="{row}">
<el-link type="info" @click="redirect(row.caseType,row.id)" <el-link type="info" @click="redirect(row.caseType,row.id)"
:disabled="(row.caseType === 'apiCase' && apiCaseReadOnly) || (row.caseType === 'scenario' && apiScenarioReadOnly) || :disabled="(row.caseType === 'apiCase' && apiCaseReadOnly) || (row.caseType === 'scenario' && apiScenarioReadOnly) ||
@ -22,17 +29,10 @@
prop="caseType" prop="caseType"
column-key="caseType" column-key="caseType"
:label="$t('home.case.case_type')" :label="$t('home.case.case_type')"
width="150" fixed
show-overflow-tooltip> show-overflow-tooltip>
<template v-slot:default="scope"> <template v-slot:default="scope">
<ms-tag v-if="scope.row.caseType === 'apiCase'" type="success" effect="plain" <basic-case-type-label :value="scope.row.caseType"></basic-case-type-label>
:content="$t('api_test.home_page.failed_case_list.table_value.case_type.api')"/>
<ms-tag v-if="scope.row.caseType === 'scenario'" type="warning" effect="plain"
:content="$t('api_test.home_page.failed_case_list.table_value.case_type.scene')"/>
<ms-tag v-if="scope.row.caseType === 'load'" type="danger" effect="plain"
:content="$t('api_test.home_page.failed_case_list.table_value.case_type.load')"/>
<ms-tag v-if="scope.row.caseType === 'testCase'" effect="plain"
:content="$t('api_test.home_page.failed_case_list.table_value.case_type.functional')"/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="testPlan" :label="$t('home.case.test_plan')"> <el-table-column prop="testPlan" :label="$t('home.case.test_plan')">
@ -45,8 +45,12 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="failureTimes" :label="$t('home.case.failure_times')" <el-table-column prop="failureTimes" :label="$t('home.case.failure_times')"
width="110" show-overflow-tooltip/> fixed show-overflow-tooltip/>
</el-table> </el-table>
<home-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize" layout="prev, pager, next, sizes"
:total="total"/>
</div>
</div>
</el-card> </el-card>
</template> </template>
@ -55,22 +59,28 @@ import MsTag from "metersphere-frontend/src/components/MsTag";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token"; import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import {homeTestPlanFailureCaseGet} from "@/api/remote/api/api-home"; import {homeTestPlanFailureCaseGet} from "@/api/remote/api/api-home";
import {hasPermission} from "@/business/utils/sdk-utils"; import {hasPermission} from "@/business/utils/sdk-utils";
import HomePagination from "@/business/home/components/pagination/HomePagination";
import BasicCaseTypeLabel from "@/business/home/components/table/BasicCaseTypeLabel";
export default { export default {
name: "MsFailureTestCaseList", name: "MsFailureTestCaseList",
components: { components: {
MsTag MsTag, HomePagination, BasicCaseTypeLabel
}, },
data() { data() {
return { return {
tableData: [], tableData: [],
loading: false, loading: false,
loadError: false,
testCaseReadOnly: false, testCaseReadOnly: false,
apiCaseReadOnly: false, apiCaseReadOnly: false,
apiScenarioReadOnly: false, apiScenarioReadOnly: false,
loadCaseReadOnly: false, loadCaseReadOnly: false,
currentPage: 1,
pageSize: 5,
total: 0,
} }
}, },
props: { props: {
@ -85,10 +95,16 @@ export default {
search() { search() {
if (this.projectId) { if (this.projectId) {
this.loading = true; this.loading = true;
homeTestPlanFailureCaseGet(this.projectId, this.selectFunctionCase, 10) this.loadError = false;
homeTestPlanFailureCaseGet(this.projectId, this.selectFunctionCase, 10, this.currentPage, this.pageSize)
.then((r) => { .then((r) => {
this.loading = false; this.loading = false;
this.tableData = r.data; this.loadError = false;
this.total = r.data.itemCount;
this.tableData = r.data.listObject;
}).catch(() => {
this.loading = false;
this.loadError = true;
}); });
} }
}, },
@ -106,8 +122,6 @@ export default {
} }
} }
}, },
created() { created() {
this.search(); this.search();
this.testCaseReadOnly = !hasPermission('PROJECT_TRACK_CASE:READ'); this.testCaseReadOnly = !hasPermission('PROJECT_TRACK_CASE:READ');
@ -122,13 +136,14 @@ export default {
</script> </script>
<style scoped> <style scoped>
.table-title {
.el-table { color: #1F2329;
cursor: pointer; font-weight: 500;
font-size: 18px!important;
line-height: 26px;
} }
.el-card :deep(.el-card__header) { .el-card :deep( .el-card__header ) {
border-bottom: 0px solid #EBEEF5; border-bottom: 0px solid #EBEEF5;
} }
</style> </style>

View File

@ -1,113 +1,129 @@
<template> <template>
<el-card class="table-card" v-loading="result.loading" body-style="padding:10px 5px;"> <el-card class="table-card" shadow="never" body-style="padding:10px 5px;">
<div slot="header"> <div slot="header">
<span class="title"> <span class="title">
{{ $t('test_track.home.relevance_case') }} {{ $t('test_track.home.relevance_case') }}
</span> </span>
</div> </div>
<!--数值统计-->
<el-container> <div v-loading="loading" element-loading-background="#FFFFFF">
<el-aside width="120px"> <div v-show="loadError"
<count-rectangle-chart :content="relevanceCountData.allRelevanceCaseCount"/> style="width: 100%; height: 300px; display: flex; flex-direction: column; justify-content: center;align-items: center">
</el-aside> <img style="height: 100px;width: 100px;"
<el-main style="padding-left: 0px;padding-right: 0px;display: block"> src="/assets/figma/icon_load_error.svg"/>
<div style="width:200px;float:right;margin:0 auto;overflow: auto"> <span class="addition-info-title" style="color: #646A73">{{ $t("home.dashboard.public.load_error") }}</span>
<el-row align="right"> </div>
<el-col :span="8" <div v-show="!loadError">
style="border-right-style: solid;border-right-width: 1px;border-right-color: #ECEEF4;"> <div class="main-info">
<div class="count-info-div" v-html="relevanceCountData.apiCaseCountStr"></div> <relevance-count-chart :relevance-data="relevanceData" ref="countChart" @redirectPage="redirectPage"/>
</div>
<div class="addition-info">
<el-row :gutter="24" style="margin: 0">
<el-col :span="24" style="padding-left: 0">
<hover-card
:title="$t('test_track.home.coverage')"
:main-info="relevanceData.coverageRage"
:tool-tip="coverRangeToolTip"
>
<!--未覆盖已覆盖-->
<template v-slot:mouseOut>
<div style="margin:16px 0px 0px 16px">
<el-row>
<el-col :span="12">
<span class="addition-info-title">
{{ $t('home.relevance_dashboard.not_cover') }}
</span>
<div class="common-amount">
<el-link class="addition-info-num" @click="redirectPage('uncoverage')">
{{ formatAmount(relevanceData.uncoverageCount) }}
</el-link>
</div>
</el-col> </el-col>
<el-col :span="8" <el-col :span="12">
style="border-right-style: solid;border-right-width: 1px;border-right-color: #ECEEF4;"> <span class="addition-info-title">
<div class="count-info-div" v-html="relevanceCountData.scenarioCaseStr"></div> {{ $t('home.relevance_dashboard.cover') }}
</el-col> </span>
<el-col :span="8" style=""> <div class="common-amount">
<div class="count-info-div" v-html="relevanceCountData.performanceCaseCountStr"></div> <el-link class="addition-info-num" @click="redirectPage('coverage')">
{{ formatAmount(relevanceData.coverageCount) }}
</el-link>
</div>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
</el-main> </template>
</el-container> </hover-card>
<!-- 本周新增-->
<el-container class="detail-container">
<el-header style="height:20px;padding: 0px;margin-bottom: 0px;font-size: 14px">
<el-row>
<el-col>
{{ $t('api_test.home_page.api_details_card.this_week_add') }}
<el-link type="info" @click="redirectPage('thisWeekRelevanceCount')" target="_blank" style="color: #000000">
{{ relevanceCountData.thisWeekAddedCount }}
</el-link>
{{ $t('api_test.home_page.unit_of_measurement') }}
</el-col> </el-col>
</el-row> </el-row>
</el-header> </div>
<el-main style="padding:0px"> </div>
<el-row> </div>
<el-col :span="8">&nbsp;</el-col>
</el-row>
</el-main>
</el-container>
<!-- 用例覆盖率率 -->
<el-container class="detail-container">
<el-header style="height:20px;padding: 0px;margin-bottom: 5px;font-size: 14px">
<el-row>
<span style="float: left">
{{ $t('test_track.home.coverage') + ":" }}&nbsp;&nbsp;
</span>
<span style="font-size: 14px">
<b>{{ relevanceCountData.coverageRage }}</b>
<el-tooltip placement="top" class="info-tool-tip">
<div slot="content">{{ $t('api_test.home_page.formula.testplan_coverage') }}</div>
<el-button icon="el-icon-info" style="padding:0px;border: 0px"></el-button>
</el-tooltip>
</span>
</el-row>
</el-header>
<el-main style="padding:0px">
<el-row>
<el-col :span="12">
<span class="default-property">
{{ $t('api_test.home_page.detail_card.uncoverage') }}
<el-link class="rows-count-number" @click="redirectPage('uncoverage')" target="_blank">
<b>
{{ relevanceCountData.uncoverageCount }}
</b>
</el-link>
</span>
</el-col>
<el-col :span="12">
<span class="main-property" style="float: right">
{{ $t('api_test.home_page.detail_card.coverage') }}
<el-link class="rows-count-number" @click="redirectPage('coverage')" target="_blank">
<b>
{{ relevanceCountData.coverageCount }}
</b>
</el-link>
</span>
</el-col>
</el-row>
</el-main>
</el-container>
</el-card> </el-card>
</template> </template>
<script> <script>
import CountRectangleChart from "metersphere-frontend/src/components/chart/CountRectangleChart"; import relevanceCountChart from "@/business/home/components/chart/RelevanceCountChart";
import hoverCard from "@/business/home/components/card/HoverCard";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import {getTrackRelevanceCount} from "@/api/track";
import {formatNumber} from "@/api/track"
export default { export default {
name: "RelevanceCaseCard", name: "RelevanceCaseCard",
components: {CountRectangleChart}, components: {relevanceCountChart, hoverCard},
props: {
relevanceCountData: {},
},
data() { data() {
return { return {
result: {} loading: false,
loadError: false,
coverRangeToolTip: this.$t('api_test.home_page.formula.testplan_coverage'),
relevanceData: {
allCaseCountNumber: 0,
allRelevanceCaseCount: 0,
apiCaseCount: 0,
apiCaseCountStr: "",
coverageCount: 0,
coverageRage: "0%",
p0CaseCountNumber: 0,
p1CaseCountNumber: 0,
p2CaseCountNumber: 0,
p3CaseCountNumber: 0,
passCount: 0,
performanceCaseCount: 0,
performanceCaseCountStr: "",
prepareCount: 0,
reviewRage: " 0%",
reviewPassRage: " 0%",
scenarioCaseCount: 0,
scenarioCaseStr: "",
thisWeekAddedCount: 0,
unPassCount: 0,
uncoverageCount: 0
},
} }
}, },
activated() {
this.search();
},
methods: { methods: {
search() {
this.loading = true;
this.loadError = false;
let selectProjectId = getCurrentProjectID();
getTrackRelevanceCount(selectProjectId)
.then(r => {
this.loading = false;
this.loadError = false;
this.trackData = r.data;
this.relevanceData = r.data;
}).catch(() => {
this.loading = false;
this.loadError = true;
this.$refs.countChart.reload();
});
},
formatAmount(number) {
return formatNumber(number);
},
redirectPage(clickType) { redirectPage(clickType) {
this.$emit("redirectPage", "testCase", "relationCase", clickType); this.$emit("redirectPage", "testCase", "relationCase", clickType);
} }

View File

@ -1,26 +1,43 @@
<template> <template>
<el-card class="table-card" v-loading="loading" body-style="padding:10px;"> <el-card class="table-card" shadow="never">
<div slot="header"> <div slot="header">
<span class="title"> <span class="table-title">
{{ $t('test_track.home.case_review') }} {{ $t('test_track.home.case_review') }}
</span> </span>
<ms-table-button v-if="!showMyCreator" icon="el-icon-view"
:content="$t('test_track.review.my_create')" @click="searchMyCreator" style="float: right"/> <div class="btn-group">
<ms-table-button v-if="showMyCreator" icon="el-icon-view" <ms-table-button icon="" :class="!showMyCreator ? 'hover' : 'reviewedBtn'" :content="$t('test_track.review.reviewed_by_me')" @click="searchMyCreator" style="border-color: #FFFFFF"/>
:content="$t('test_track.review.reviewed_by_me')" @click="searchMyCreator" style="float: right"/> <ms-table-button icon="" :class="showMyCreator ? 'hover' : 'createBtn'" :content="$t('test_track.review.my_create')" @click="searchMyCreator" style="border-color: #FFFFFF; margin-left: 3px"/>
</div> </div>
</div>
<div v-loading="loading" element-loading-background="#FFFFFF">
<div v-show="loadError"
style="width: 100%; height: 300px; display: flex; flex-direction: column; justify-content: center;align-items: center">
<img style="height: 100px;width: 100px;"
src="/assets/figma/icon_load_error.svg"/>
<span class="addition-info-title" style="color: #646A73">{{ $t("home.dashboard.public.load_error") }}</span>
</div>
<div v-show="!loadError">
<el-table <el-table
class="adjust-table" class="adjust-table"
border
:data="tableData" :data="tableData"
@row-click="intoPlan" @row-click="intoPlan"
v-loading="loading" height="300px"> :header-cell-style="{backgroundColor: '#F5F6F7'}"
v-loading="loading" height="224px">
<el-table-column type="index" fixed :label="$t('home.table.index')" show-overflow-tooltip></el-table-column>
<el-table-column <el-table-column
prop="name" prop="name"
fixed fixed
:label="$t('commons.name')" :label="$t('commons.name')"
show-overflow-tooltip> show-overflow-tooltip>
</el-table-column> </el-table-column>
<el-table-column
prop="status"
:label="$t('test_track.plan.plan_status')">
<template v-slot:default="scope">
<basic-status-label :value="scope.row.status"></basic-status-label>
</template>
</el-table-column>
<el-table-column <el-table-column
prop="creator" prop="creator"
fixed fixed
@ -33,15 +50,6 @@
:label="$t('test_track.review.reviewer')" :label="$t('test_track.review.reviewer')"
show-overflow-tooltip> show-overflow-tooltip>
</el-table-column> </el-table-column>
<el-table-column
prop="status"
:label="$t('test_track.plan.plan_status')">
<template v-slot:default="scope">
<plan-status-table-item :value="scope.row.status"/>
</template>
</el-table-column>
<el-table-column <el-table-column
:label="$t('test_track.review.result_distribution')"> :label="$t('test_track.review.result_distribution')">
<template v-slot:default="scope"> <template v-slot:default="scope">
@ -53,53 +61,62 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
<home-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize" layout="prev, pager, next, sizes"
:total="total"/>
</div>
</div>
</el-card> </el-card>
</template> </template>
<script> <script>
import MsTableOperator from "metersphere-frontend/src/components/MsTableOperator"; import MsTableOperator from "metersphere-frontend/src/components/MsTableOperator";
import PlanStageTableItem from "../../common/tableItems/plan/PlanStageTableItem";
import PlanStatusTableItem from "../../common/tableItems/plan/PlanStatusTableItem";
import HomeBaseComponent from "./HomeBaseComponent"; import HomeBaseComponent from "./HomeBaseComponent";
import MsTableButton from "metersphere-frontend/src/components/MsTableButton"; import MsTableButton from "metersphere-frontend/src/components/MsTableButton";
import {getCurrentProjectID, getCurrentWorkspaceId} from "metersphere-frontend/src/utils/token"; import {getCurrentProjectID, getCurrentWorkspaceId} from "metersphere-frontend/src/utils/token";
import {getRelateTestCaseReview} from "@/api/test-review"; import {getRelateTestCaseReview} from "@/api/test-review";
import HomePagination from "@/business/home/components/pagination/HomePagination";
import BasicStatusLabel from "@/business/home/components/table/BasicStatusLabel";
import BasicStatus from "@/business/home/components/table/BasicStatusLabel";
export default { export default {
name: "ReviewList", name: "ReviewList",
components: {MsTableOperator, PlanStageTableItem, PlanStatusTableItem, HomeBaseComponent, MsTableButton}, components: {BasicStatus, MsTableOperator, HomeBaseComponent, MsTableButton, HomePagination, BasicStatusLabel},
data() { data() {
return { return {
loading: false, loading: false,
loadError: false,
tableData: [], tableData: [],
showMyCreator: false, showMyCreator: false,
currentPage: 1,
pageSize: 5,
total: 0,
tip: [ tip: [
{text: "X", fillStyle: '#D3D3D3'}, {text: "X", fillStyle: '#1F232926'},
{text: "X", fillStyle: '#ee4545'}, {text: "X", fillStyle: '#F76964'},
{text: "X", fillStyle: '#4dcf4d'} {text: "X", fillStyle: '#AA4FBF'}
] ]
} }
}, },
mounted() { mounted() {
this.initTableData(''); this.search();
}, },
methods: { methods: {
initTableData(type) { search() {
if (!type) { let type = this.showMyCreator ? 'creator' : 'reviewer';
type = 'reviewer'
}
let projectId = getCurrentProjectID(); let projectId = getCurrentProjectID();
let workspaceId = getCurrentWorkspaceId(); let workspaceId = getCurrentWorkspaceId();
if (!projectId) {
return;
}
let param = {type, projectId, workspaceId}; let param = {type, projectId, workspaceId};
this.loading = true; this.loading = true;
getRelateTestCaseReview(param) this.loadError = false;
getRelateTestCaseReview(this.currentPage, this.pageSize, param)
.then((r) => { .then((r) => {
this.total = r.data.itemCount;
this.tableData = r.data.listObject;
this.loading = false; this.loading = false;
this.tableData = r.data; this.loadError = false;
}).catch(() => {
this.loading = false;
this.loadError = true;
}); });
}, },
intoPlan(row) { intoPlan(row) {
@ -107,11 +124,7 @@ export default {
}, },
searchMyCreator() { searchMyCreator() {
this.showMyCreator = !this.showMyCreator; this.showMyCreator = !this.showMyCreator;
if (this.showMyCreator) { this.search();
this.initTableData("creator");
} else {
this.initTableData("reviewer");
}
}, },
getResultTip(total, reviewed, pass) { getResultTip(total, reviewed, pass) {
return '通过: ' + pass + '; ' + '未通过: ' + (reviewed - pass) + '; ' + '未评审: ' + (total - reviewed); return '通过: ' + pass + '; ' + '未通过: ' + (reviewed - pass) + '; ' + '未评审: ' + (total - reviewed);
@ -121,7 +134,40 @@ export default {
</script> </script>
<style scoped> <style scoped>
.table-title {
color: #1F2329;
font-weight: 500;
font-size: 18px!important;
line-height: 26px;
}
.el-card :deep( .el-card__header ) { .el-card :deep( .el-card__header ) {
border-bottom: 0px solid #EBEEF5; border-bottom: 0px solid #EBEEF5;
} }
.btn-group {
float: right;
background: #FFFFFF;
border: 1px solid #BBBFC4;
border-radius: 4px;
margin: 1px;
}
:deep(button.el-button.el-button--mini.is-plain.hover) {
background: rgba(120, 56, 135, 0.1);
border-radius: 4px;
color: #783887;
}
.reviewedBtn.el-button--mini.is-plain:hover {
background: rgba(120, 56, 135, 0.1);
border-radius: 4px;
color: #783887;
}
.createBtn.el-button--mini.is-plain:hover {
background: rgba(120, 56, 135, 0.1);
border-radius: 4px;
color: #783887;
}
</style> </style>

View File

@ -1,19 +1,26 @@
<template> <template>
<el-card class="table-card" v-loading="loading" body-style="padding:10px;"> <el-card class="table-card" shadow="never">
<template v-slot:header> <template v-slot:header>
<span class="title"> <span class="table-title">
{{ $t('api_test.home_page.running_task_list.title') }} {{ $t('api_test.home_page.running_task_list.title') }}
</span> </span>
</template> </template>
<ms-table <div v-loading="loading" element-loading-background="#FFFFFF">
<div v-show="loadError"
style="width: 100%; height: 300px; display: flex; flex-direction: column; justify-content: center;align-items: center">
<img style="height: 100px;width: 100px;"
src="/assets/figma/icon_load_error.svg"/>
<span class="addition-info-title" style="color: #646A73">{{ $t("home.dashboard.public.load_error") }}</span>
</div>
<div v-show="!loadError">
<el-table
:enable-selection="false" :enable-selection="false"
:condition="condition" :condition="condition"
:data="tableData" :data="tableData"
@refresh="search" :header-cell-style="{backgroundColor: '#F5F6F7'}"
screen-height="300px"> @refresh="search" height="224px">
<el-table-column prop="index" :label="$t('home.table.index')" width="80" <el-table-column prop="index" :label="$t('home.table.index')" fixed show-overflow-tooltip/>
show-overflow-tooltip/> <el-table-column prop="name" :label="$t('commons.name')" fixed>
<el-table-column prop="name" :label="$t('commons.name')" width="200">
<template v-slot:default="{row}"> <template v-slot:default="{row}">
<!-- 若为只读用户不可点击之后跳转--> <!-- 若为只读用户不可点击之后跳转-->
<span v-if="isReadOnly"> <span v-if="isReadOnly">
@ -27,19 +34,13 @@
<ms-table-column <ms-table-column
prop="taskType" prop="taskType"
:filters="typeFilters" :filters="typeFilters"
:label="$t('home.table.task_type')" width="120"> :label="$t('home.table.task_type')" fixed>
<template v-slot:default="scope"> <template v-slot:default="scope">
<ms-tag v-if="scope.row.taskGroup == 'API_SCENARIO_TEST'" type="success" effect="plain" <basic-task-type-label :value="scope.row.taskGroup"></basic-task-type-label>
:content="$t('api_test.home_page.running_task_list.scenario_schedule')"/>
<ms-tag v-if="scope.row.taskGroup == 'TEST_PLAN_TEST'" type="warning" effect="plain"
:content="$t('api_test.home_page.running_task_list.test_plan_schedule')"/>
<ms-tag v-if="scope.row.taskGroup == 'SWAGGER_IMPORT'" type="danger" effect="plain"
:content="$t('api_test.home_page.running_task_list.swagger_schedule')"/>
</template> </template>
</ms-table-column> </ms-table-column>
<el-table-column prop="rule" :label="$t('home.table.run_rule')" width="120" <el-table-column prop="rule" :label="$t('home.table.run_rule')" fixed show-overflow-tooltip/>
show-overflow-tooltip/> <el-table-column fixed :label="$t('home.table.task_status')">
<el-table-column width="100" :label="$t('home.table.task_status')">
<template v-slot:default="scope"> <template v-slot:default="scope">
<div> <div>
<el-switch <el-switch
@ -50,23 +51,24 @@
></el-switch> ></el-switch>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column width="170" :label="$t('home.table.next_execution_time')"> <el-table-column fixed :label="$t('home.table.next_execution_time')">
<template v-slot:default="scope"> <template v-slot:default="scope">
<span>{{ scope.row.nextExecutionTime | datetimeFormat }}</span> <span>{{ scope.row.nextExecutionTime | datetimeFormat }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="creator" :label="$t('home.table.create_user')" <el-table-column prop="creator" :label="$t('home.table.create_user')"
width="100" show-overflow-tooltip/> fixed show-overflow-tooltip/>
<el-table-column width="170" :label="$t('home.table.update_time')"> <el-table-column fixed :label="$t('home.table.update_time')">
<template v-slot:default="scope"> <template v-slot:default="scope">
<span>{{ scope.row.updateTime | datetimeFormat }}</span> <span>{{ scope.row.updateTime | datetimeFormat }}</span>
</template> </template>
</el-table-column> </el-table-column>
</el-table>
</ms-table> <home-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize" layout="prev, pager, next, sizes"
:total="total"/>
</div>
</div>
</el-card> </el-card>
</template> </template>
@ -77,14 +79,12 @@ import MsTable from "metersphere-frontend/src/components/table/MsTable";
import MsTableColumn from "metersphere-frontend/src/components/table/MsTableColumn"; import MsTableColumn from "metersphere-frontend/src/components/table/MsTableColumn";
import {getTrackRunningTask} from "@/api/track"; import {getTrackRunningTask} from "@/api/track";
import {updatePlanSchedule} from "@/api/remote/plan/test-plan"; import {updatePlanSchedule} from "@/api/remote/plan/test-plan";
import HomePagination from "@/business/home/components/pagination/HomePagination";
import BasicTaskTypeLabel from "@/business/home/components/table/BasicTaskTypeLabel";
export default { export default {
name: "MsRunningTaskList", name: "MsRunningTaskList",
components: { components: { MsTableColumn, MsTable, MsTag, HomePagination, BasicTaskTypeLabel },
MsTableColumn,
MsTable,
MsTag
},
props: { props: {
callFrom: String, callFrom: String,
}, },
@ -94,6 +94,10 @@ export default {
tableData: [], tableData: [],
visible: false, visible: false,
loading: false, loading: false,
loadError: false,
currentPage: 1,
pageSize: 5,
total: 0,
typeFilters: [], typeFilters: [],
condition: { condition: {
filters: {} filters: {}
@ -126,14 +130,19 @@ export default {
} }
if (this.projectId) { if (this.projectId) {
this.loading = true; this.loading = true;
getTrackRunningTask(this.projectId, this.condition) this.loadError = false;
getTrackRunningTask(this.projectId, this.currentPage, this.pageSize, this.condition)
.then((r) => { .then((r) => {
this.loading = false; this.loading = false;
this.tableData = r.data; this.loadError = false;
this.total = r.data.itemCount;
this.tableData = r.data.listObject;
}).catch(() => {
this.loading = false;
this.loadError = true;
}); });
} }
}, },
closeTaskConfirm(row) { closeTaskConfirm(row) {
let flag = row.taskStatus; let flag = row.taskStatus;
row.taskStatus = !flag; //switch row.taskStatus = !flag; //switch
@ -174,6 +183,12 @@ export default {
</script> </script>
<style scoped> <style scoped>
.table-title {
color: #1F2329;
font-weight: 500;
font-size: 18px!important;
line-height: 26px;
}
.el-table { .el-table {
cursor: pointer; cursor: pointer;
@ -182,5 +197,4 @@ export default {
.el-card :deep( .el-card__header ) { .el-card :deep( .el-card__header ) {
border-bottom: 0px solid #EBEEF5; border-bottom: 0px solid #EBEEF5;
} }
</style> </style>

View File

@ -0,0 +1,71 @@
<template>
<div class="hover-card-main"
@mouseleave="isHover=false">
<transition name="el-zoom-in-top">
<div v-show="!isHover" class="transition-box">
<div style="margin:16px 0 0 16px">
<span class="addition-info-title"> {{ title }}</span>
<el-tooltip class="item" effect="light" :content="toolTip" placement="top-start">
<img style="height: 14px;width: 14px;margin-left: 4px" src="/assets/figma/icon_question.svg"/>
</el-tooltip>
<div class="common-amount" @mouseenter="isHover=true">
<span class="addition-info-text">
{{ mainInfo }}
</span>
</div>
</div>
</div>
</transition>
<transition name="el-zoom-in-bottom">
<div v-show="isHover" class="transition-box-hover">
<slot name="mouseOut"></slot>
</div>
</transition>
</div>
</template>
<script>
export default {
name: "HoverCard",
data() {
return {
isHover: false,
}
},
props: {
title: String,
mainInfo: [String, Number],
toolTip: String,
},
methods: {}
}
</script>
<style scoped>
.hover-card-main {
box-sizing: border-box;
height: 86px;
background-color: #FFFFFF;
position: relative;
}
.transition-box {
height: 100%;
width: 100%;
background-color: #FFFFFF;
box-sizing: border-box;
position: absolute;
border: 1px solid #DEE0E3;
border-radius: 4px;
}
.transition-box-hover {
height: 100%;
width: 100%;
background-color: #F5F6F7;
box-sizing: border-box;
position: absolute;
border: 1px solid #DEE0E3;
border-radius: 4px;
}
</style>

View File

@ -0,0 +1,114 @@
<template>
<div class="main-info-card">
<div style="margin:16px">
<span class="main-info-card-title">
{{ title }}
</span>
<div style="margin-top: 4px;height: 40px">
<span v-if="isExecuteInfo" class="addition-num">{{ countData.executedTimesInWeek }}</span>
<span v-else class="main-num">{{ countData.total }}</span>
</div>
<div style="margin-top: 32px">
<div v-if="isExecuteInfo">
<span class="main-info-card-title">{{ $t("home.dashboard.public.executed_times") }}</span>
<div class="common-amount">
<span class="addition-num">
{{ countData.executedTimes }}
</span>
</div>
</div>
<div v-else>
<el-row>
<el-col :span="12">
<span class="main-info-card-title">{{ $t("home.dashboard.public.this_week") }}</span>
<div class="common-amount">
<el-button class="common-amount-button" @click="redirect('createdInWeek')">
<span type="num" class="addition-num">
+{{ countData.createdInWeek }}
</span>
<img class="main-info-card-right" src="/assets/figma/icon_right_outlined.svg" alt="">
</el-button>
</div>
</el-col>
<el-col :span="12">
<span class="main-info-card-title">{{ $t("home.dashboard.public.fake_error") }}</span>
<div class="common-amount">
<el-button class="common-amount-button" @click="redirect('fakeError')">
<span class="addition-num">
{{ countData.fakeErrorCount }}
</span>
<img class="main-info-card-right" src="/assets/figma/icon_right_outlined.svg" alt="">
</el-button>
</div>
</el-col>
</el-row>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "MainInfoCard",
props: {
title: String,
isExecuteInfo: Boolean,
countData: Object,
redirectPageName: String,
redirectDataType: String,
},
methods: {
redirect(seletDataType) {
this.$emit('redirectPage', this.redirectPageName, this.redirectDataType, seletDataType, null);
}
}
}
</script>
<style scoped>
.main-info-card {
font-size: 14px;
font-weight: 400;
line-height: 22px;
}
.addition-num {
font-size: 20px;
font-weight: 500;
line-height: 28px;
}
.main-num {
font-size: 32px;
font-weight: 500;
line-height: 40px;
}
.common-amount-button {
padding: 0 4px 0 4px;
border: 0;
margin: 0 -4px 0 -8px;
}
.common-amount-button :deep(.addition-num) {
margin: 0 -4px 0 4px;
}
.main-info-card-right {
height: 12px;
width: 12px;
}
.common-amount-button:focus img {
transform: translateY(-999999px);
filter: drop-shadow(#783887 0px 999999px);
}
.common-amount-button:hover img {
transform: translateY(-999999px);
filter: drop-shadow(#783887 0px 999999px);
}
</style>

View File

@ -0,0 +1,242 @@
<template>
<div v-if="reloadOver">
<el-row type="flex" justify="left" align="left">
<div style="height: 184px;width: 184px;margin-left: 30px;margin-right: 30px;">
<ms-chart :options="options"
:height="184"
:width="184"
:autoresize="true"/>
</div>
<!-- 总数统计 -->
<div style="margin: auto;width: 260px;padding-right: 30px">
<div class="count-row">
<span class="ms-point-p3"/>
<span class="count-title">P3</span>
<span class="count-value">
{{ formatAmount(bugData.unClosedP3Size) }}
</span>
</div>
<div class="count-row">
<span class="ms-point-p2"/>
<span class="count-title">P2</span>
<span class="count-value">
{{ formatAmount(bugData.unClosedP2Size) }}
</span>
</div>
<div class="count-row">
<span class="ms-point-p1"/>
<span class="count-title">P1</span>
<span class="count-value">
{{ formatAmount(bugData.unClosedP1Size) }}
</span>
</div>
<div class="count-row">
<div>
<span class="ms-point-p0"/>
<span class="count-title">P0</span>
<span class="count-value">
{{ formatAmount(bugData.unClosedP0Size) }}
</span>
</div>
</div>
</div>
</el-row>
</div>
</template>
<script>
import MsChart from "metersphere-frontend/src/components/chart/MsChart";
import {getUUID} from "metersphere-frontend/src/utils";
import {formatNumber} from "@/api/track";
export default {
name: "CountChart",
components: {MsChart},
props: {
bugData: Object,
totalTime: Number,
isExport: {
type: Boolean,
default: false,
}
},
data() {
return {
reloadOver: true,
pieChartStyle: {
amountFontSize: 32,
},
}
},
created() {
},
methods: {
reload() {
this.reloadOver = false;
this.$nextTick(() => {
this.reloadOver = true;
});
},
getTotal() {
let total = 0;
if (this.bugData.unClosedP0Size) {
total += this.bugData.unClosedP0Size;
}
if (this.bugData.unClosedP1Size) {
total += this.bugData.unClosedP1Size;
}
if (this.bugData.unClosedP2Size) {
total += this.bugData.unClosedP2Size;
}
if (this.bugData.unClosedP3Size) {
total += this.bugData.unClosedP3Size;
}
return total;
},
getAmount() {
let total = this.getTotal();
if (total > 999999999) {
this.pieChartStyle.amountFontSize = 20;
} else if (total > 99999999) {
this.pieChartStyle.amountFontSize = 22;
} else if (total > 9999999) {
this.pieChartStyle.amountFontSize = 24;
} else if (total > 999999) {
this.pieChartStyle.amountFontSize = 26;
} else {
this.pieChartStyle.amountFontSize = 32;
}
total = this.formatAmount(total);
return total;
},
formatAmount(param) {
return formatNumber(param);
}
},
computed: {
options() {
let protocolData = [{value: 0}];
let colorArr = ['#DEE0E3'];
if (this.getTotal() > 0) {
colorArr = ['#F54A45', '#FFD131', '#C1A9C8', '#10CECE',]
protocolData = [
{value: this.bugData.unClosedP3Size, name: 'P3'},
{value: this.bugData.unClosedP2Size, name: 'P2'},
{value: this.bugData.unClosedP1Size, name: 'P1'},
{value: this.bugData.unClosedP0Size, name: 'P0'},
];
}
let optionData = {
color: colorArr,
tooltip: {
trigger: 'item'
},
title: {
text: "{mainTitle|" + this.$t("home.bug_dashboard.un_closed_bug_count") + "}\n\n{number|" + this.getAmount() + "}\n\n",
// subtext: this.$t("home.dashboard.public.this_week") + ": +" + this.relevanceData.thisWeekAddedCount + " >",
top: "center",
left: "center",
textStyle: {
rich: {
mainTitle: {
color: '#646A73',
fontSize: 12,
},
number: {
fontSize: this.pieChartStyle.amountFontSize,
fontWeight: 500,
fontStyle: "normal",
fontFamily: "PinfFang SC",
margin: "112px 0px 0px 2px0",
},
}
},
// sublink: "/#/track/case/all/" + getUUID() + "/case/thisWeekRelevanceCount",
// subtextStyle: {
// color: "#1F2329",
// fontSize: 12,
// width: 105,
// ellipsis: '... >',
// overflow: "truncate",
// },
itemGap: -60,
},
series: [
{
type: 'pie',
radius: ['75%', '96%'],
avoidLabelOverlap: false,
hoverAnimation: true,
label: {
show: false,
},
itemStyle: {
borderColor: "#FFF",
borderWidth: 3,
borderRadius: 1,
},
labelLine: {
show: false
},
data: protocolData,
}
]
};
return optionData;
},
},
}
</script>
<style scoped>
.count-row {
padding: 8px 0px 8px 0px;
}
.count-title {
color: #646A73;
font-size: 14px;
font-weight: 400;
}
.count-value {
color: #646A73;
float: right;
font-size: 14px;
font-weight: 500;
}
.ms-point-p3 {
height: 8px;
width: 8px;
margin-right: 8px;
display: inline-block;
background-color: #F54A45;
}
.ms-point-p2 {
height: 8px;
width: 8px;
margin-right: 8px;
display: inline-block;
background-color: #FFD131;
}
.ms-point-p1 {
height: 8px;
width: 8px;
margin-right: 8px;
display: inline-block;
background-color: #C1A9C8;
}
.ms-point-p0 {
height: 8px;
width: 8px;
margin-right: 8px;
display: inline-block;
background-color: #10CECE;
}
</style>

View File

@ -0,0 +1,241 @@
<template>
<div v-if="reloadOver">
<el-row type="flex" justify="left" align="left">
<div style="height: 184px;width: 184px;margin-left: 30px;margin-right: 30px;">
<ms-chart :options="options"
:height="184"
:width="184"
:autoresize="true"/>
</div>
<!-- 总数统计 -->
<div style="margin: auto;width: 260px;padding-right: 30px">
<div class="count-row">
<div>
<span class="ms-point-p0"/>
<span class="count-title">P0</span>
<span class="count-value">
{{ formatAmount(trackData.p0CaseCountNumber) }}
</span>
</div>
</div>
<div class="count-row">
<span class="ms-point-p1"/>
<span class="count-title">P1</span>
<span class="count-value">
{{ formatAmount(trackData.p1CaseCountNumber) }}
</span>
</div>
<div class="count-row">
<span class="ms-point-p2"/>
<span class="count-title">P2</span>
<span class="count-value">
{{ formatAmount(trackData.p2CaseCountNumber) }}
</span>
</div>
<div class="count-row">
<span class="ms-point-p3"/>
<span class="count-title">P3</span>
<span class="count-value">
{{ formatAmount(trackData.p3CaseCountNumber) }}
</span>
</div>
</div>
</el-row>
</div>
</template>
<script>
import MsChart from "metersphere-frontend/src/components/chart/MsChart";
import {getUUID} from "metersphere-frontend/src/utils";
import {formatNumber} from "@/api/track";
export default {
name: "CaseCountChart",
components: {MsChart},
props: {
trackData: Object,
totalTime: Number,
isExport: {
type: Boolean,
default: false,
}
},
data() {
return {
reloadOver: true,
pieChartStyle: {
amountFontSize: 32,
},
}
},
created() {
},
methods: {
reload() {
this.reloadOver = false;
this.$nextTick(() => {
this.reloadOver = true;
});
},
getTotal() {
let total = 0;
if (this.trackData.p0CaseCountNumber) {
total += this.trackData.p0CaseCountNumber;
}
if (this.trackData.p0CaseCountNumber) {
total += this.trackData.p1CaseCountNumber;
}
if (this.trackData.p0CaseCountNumber) {
total += this.trackData.p2CaseCountNumber;
}
if (this.trackData.p0CaseCountNumber) {
total += this.trackData.p3CaseCountNumber;
}
return total;
},
getAmount() {
let total = this.getTotal();
if (total > 999999999) {
this.pieChartStyle.amountFontSize = 20;
} else if (total > 99999999) {
this.pieChartStyle.amountFontSize = 22;
} else if (total > 9999999) {
this.pieChartStyle.amountFontSize = 24;
} else if (total > 999999) {
this.pieChartStyle.amountFontSize = 26;
} else {
this.pieChartStyle.amountFontSize = 32;
}
total = this.formatAmount(total);
return total;
},
formatAmount(param) {
return formatNumber(param);
}
},
computed: {
options() {
let protocolData = [{value: 0}];
let colorArr = ['#DEE0E3'];
if (this.getTotal() > 0) {
colorArr = ['#AA4FBF', '#FFD131', '#10CECE', '#4261F6',]
protocolData = [
{value: this.trackData.p0CaseCountNumber, name: 'P0'},
{value: this.trackData.p1CaseCountNumber, name: 'P1'},
{value: this.trackData.p2CaseCountNumber, name: 'P2'},
{value: this.trackData.p3CaseCountNumber, name: 'P3'},
];
}
let optionData = {
color: colorArr,
tooltip: {
trigger: 'item'
},
title: {
text: "{mainTitle|" + this.$t("home.case_review_dashboard.case_count") + "}\n\n{number|" + this.getAmount() + "}\n\n",
subtext: this.$t("home.dashboard.public.this_week") + ": +" + this.trackData.thisWeekAddedCount + " >",
top: "center",
left: "center",
textStyle: {
rich: {
mainTitle: {
color: '#646A73',
fontSize: 12,
},
number: {
fontSize: this.pieChartStyle.amountFontSize,
fontWeight: 500,
fontStyle: "normal",
fontFamily: "PinfFang SC",
margin: "112px 0px 0px 2px0",
},
}
},
sublink: "/#/track/case/all/" + getUUID() + "/case/thisWeekCount",
subtextStyle: {
color: "#1F2329",
fontSize: 12,
width: 105,
ellipsis: '...',
overflow: "truncate",
},
itemGap: -60,
},
series: [
{
type: 'pie',
radius: ['70%', '96%'],
avoidLabelOverlap: false,
hoverAnimation: true,
label: {
show: false,
},
itemStyle: {
borderColor: "#FFF",
borderWidth: 3,
borderRadius: 1,
},
labelLine: {
show: false
},
data: protocolData,
}
]
};
return optionData;
},
},
}
</script>
<style scoped>
.count-row {
padding: 8px 0px 8px 0px;
}
.count-title {
color: #646A73;
font-size: 14px;
font-weight: 400;
}
.count-value {
color: #646A73;
float: right;
font-size: 14px;
font-weight: 500;
}
.ms-point-p0 {
height: 8px;
width: 8px;
margin-right: 8px;
display: inline-block;
background-color: #AA4FBF;
}
.ms-point-p1 {
height: 8px;
width: 8px;
margin-right: 8px;
display: inline-block;
background-color: #FFD131;
}
.ms-point-p2 {
height: 8px;
width: 8px;
margin-right: 8px;
display: inline-block;
background-color: #10CECE;
}
.ms-point-p3 {
height: 8px;
width: 8px;
margin-right: 8px;
display: inline-block;
background-color: #4261F6;
}
</style>

View File

@ -0,0 +1,223 @@
<template>
<div v-if="reloadOver">
<el-row type="flex" justify="left" align="left">
<div style="height: 184px;width: 184px;margin-left: 30px;margin-right: 30px;">
<ms-chart :options="options"
:height="184"
:width="184"
:autoresize="true"/>
</div>
<!-- 总数统计 -->
<div style="margin: auto;width: 260px;padding-right: 30px">
<div class="count-row">
<div>
<span class="ms-point-api"/>
<span class="count-title">{{ $t('home.relevance_dashboard.api_case') }}</span>
<span class="count-value">
{{ formatAmount(relevanceData.apiCaseCount) }}
</span>
</div>
</div>
<div class="count-row">
<span class="ms-point-scenario"/>
<span class="count-title">{{ $t('home.relevance_dashboard.scenario_case') }}</span>
<span class="count-value">
{{ formatAmount(relevanceData.scenarioCaseCount) }}
</span>
</div>
<div class="count-row">
<span class="ms-point-performance"/>
<span class="count-title">{{ $t('home.relevance_dashboard.performance_case') }}</span>
<span class="count-value">
{{ formatAmount(relevanceData.performanceCaseCount) }}
</span>
</div>
</div>
</el-row>
</div>
</template>
<script>
import MsChart from "metersphere-frontend/src/components/chart/MsChart";
import {getUUID} from "metersphere-frontend/src/utils";
import {formatNumber} from "@/api/track";
export default {
name: "RelevanceCountChart",
components: {MsChart},
props: {
relevanceData: Object,
totalTime: Number,
isExport: {
type: Boolean,
default: false,
}
},
data() {
return {
reloadOver: true,
pieChartStyle: {
amountFontSize: 32,
},
}
},
created() {
},
methods: {
reload() {
this.reloadOver = false;
this.$nextTick(() => {
this.reloadOver = true;
});
},
getTotal() {
let total = 0;
if (this.relevanceData.apiCaseCount) {
total += this.relevanceData.apiCaseCount;
}
if (this.relevanceData.scenarioCaseCount) {
total += this.relevanceData.scenarioCaseCount;
}
if (this.relevanceData.performanceCaseCount) {
total += this.relevanceData.performanceCaseCount;
}
return total;
},
getAmount() {
let total = this.getTotal();
if (total > 999999999) {
this.pieChartStyle.amountFontSize = 20;
} else if (total > 99999999) {
this.pieChartStyle.amountFontSize = 22;
} else if (total > 9999999) {
this.pieChartStyle.amountFontSize = 24;
} else if (total > 999999) {
this.pieChartStyle.amountFontSize = 26;
} else {
this.pieChartStyle.amountFontSize = 32;
}
total = this.formatAmount(total);
return total;
},
formatAmount(param) {
return formatNumber(param);
}
},
computed: {
options() {
let protocolData = [{value: 0}];
let colorArr = ['#DEE0E3'];
if (this.getTotal() > 0) {
colorArr = ['#AA4FBF', '#FFD131', '#10CECE', '#4261F6',]
protocolData = [
{value: this.relevanceData.apiCaseCount, name: this.$t('home.relevance_dashboard.api_case')},
{value: this.relevanceData.scenarioCaseCount, name: this.$t('home.relevance_dashboard.scenario_case')},
{value: this.relevanceData.performanceCaseCount, name: this.$t('home.relevance_dashboard.performance_case')}
];
}
let optionData = {
color: colorArr,
tooltip: {
trigger: 'item'
},
title: {
text: "{mainTitle|" + this.$t("home.relevance_dashboard.relevance_case_count") + "}\n\n{number|" + this.getAmount() + "}\n\n",
subtext: this.$t("home.dashboard.public.this_week") + ": +" + this.relevanceData.thisWeekAddedCount + " >",
top: "center",
left: "center",
textStyle: {
rich: {
mainTitle: {
color: '#646A73',
fontSize: 12,
},
number: {
fontSize: this.pieChartStyle.amountFontSize,
fontWeight: 500,
fontStyle: "normal",
fontFamily: "PinfFang SC",
margin: "112px 0px 0px 2px0",
},
}
},
sublink: "/#/track/case/all/" + getUUID() + "/case/thisWeekRelevanceCount",
subtextStyle: {
color: "#1F2329",
fontSize: 12,
width: 105,
ellipsis: '...',
overflow: "truncate",
},
itemGap: -60,
},
series: [
{
type: 'pie',
radius: ['70%', '96%'],
avoidLabelOverlap: false,
hoverAnimation: true,
label: {
show: false,
},
itemStyle: {
borderColor: "#FFF",
borderWidth: 3,
borderRadius: 1,
},
labelLine: {
show: false
},
data: protocolData,
}
]
};
return optionData;
},
},
}
</script>
<style scoped>
.count-row {
padding: 8px 0px 8px 0px;
}
.count-title {
color: #646A73;
font-size: 14px;
font-weight: 400;
}
.count-value {
color: #646A73;
float: right;
font-size: 14px;
font-weight: 500;
}
.ms-point-api {
height: 8px;
width: 8px;
margin-right: 8px;
display: inline-block;
background-color: #AA4FBF;
}
.ms-point-scenario {
height: 8px;
width: 8px;
margin-right: 8px;
display: inline-block;
background-color: #FFD131;
}
.ms-point-performance {
height: 8px;
width: 8px;
margin-right: 8px;
display: inline-block;
background-color: #10CECE;
}
</style>

View File

@ -0,0 +1,113 @@
<template>
<el-row type="flex" justify="end">
<div class="table-page">
<el-pagination
class="home-pagination"
background
:pager-count="5"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="pageSizes"
:page-size="pageSize"
:layout="layout"
:total="total">
</el-pagination>
</div>
</el-row>
</template>
<script>
export default {
name: "MsTablePagination",
props: {
page: Object,
currentPage: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 5
},
pageSizes: {
type: Array,
default: function () {
return [5, 10, 20, 50]
}
},
total: {
type: Number,
default: 0
},
layout: {
type: String,
default() {
return 'total, sizes, prev, pager, next, jumper';
}
},
change: Function
},
methods: {
handleSizeChange: function (size) {
this.$emit('update:pageSize', size)
this.change();
},
handleCurrentChange(current) {
this.$emit('update:currentPage', current)
this.change();
}
}
}
</script>
<style scoped>
.table-page {
padding-top: 10px;
}
.table-page {
padding-top: 10px;
}
:deep(.home-pagination.el-pagination.is-background .el-pager li) {
background-color: #FFFFFF;
color: #1F2329;
border: 1px solid #BBBFC4;
width: 28px;
height: 28px;
box-sizing: border-box;
border-radius: 4px;
font-size: 14px;
font-weight: 400;
line-height: 26px;
}
:deep(.home-pagination.el-pagination.is-background .el-pager li:not(.disabled).active) {
background-color: #FFFFFF;
color: #783887;
border: 1px solid #783887;
}
:deep(.home-pagination.el-pagination.is-background .btn-next,) {
background-color: #FFFFFF;
border: 1px solid #BBBFC4;
width: 28px;
height: 28px;
box-sizing: border-box;
border-radius: 4px;
font-size: 14px;
font-weight: 400;
line-height: 26px;
}
:deep(.home-pagination.el-pagination.is-background .btn-prev) {
background-color: #FFFFFF;
border: 1px solid #BBBFC4;
width: 28px;
height: 28px;
box-sizing: border-box;
border-radius: 4px;
font-size: 14px;
font-weight: 400;
line-height: 26px;
}
</style>

View File

@ -0,0 +1,60 @@
<template>
<span>
<el-tag v-if="value === 'apiCase'" class="status-label api">
{{ $t('api_test.home_page.failed_case_list.table_value.case_type.api') }}
</el-tag>
<el-tag v-if="value === 'scenario'" class="status-label scene">
{{ $t('api_test.home_page.failed_case_list.table_value.case_type.scene') }}
</el-tag>
<el-tag v-if="value === 'load'" class="status-label load">
{{ $t('api_test.home_page.failed_case_list.table_value.case_type.load') }}
</el-tag>
<el-tag v-if="value === 'testCase'" class="status-label functional">
{{ $t('api_test.home_page.failed_case_list.table_value.case_type.functional') }}
</el-tag>
</span>
</template>
<script>
export default {
name: "BasicStatus",
components: {},
props: {
value: {
type: String
}
}
}
</script>
<style scoped>
.status-label {
height: 24px;
font-weight: 400;
font-size: 14px;
line-height: 22px;
padding: 1px 6px;
border-radius: 2px;
border-color: transparent;
}
.api {
background-color: rgba(52, 199, 36, 0.2);
color: #2EA121;
}
.scene {
background-color: rgba(52, 199, 36, 0.2);
color: #2EA121;
}
.load {
background-color: rgba(255, 136, 0, 0.2);
color: #DE7802;
}
.functional {
background-color: rgba(51, 112, 255, 0.2);
color: #245BDB;
}
</style>

View File

@ -0,0 +1,76 @@
<template>
<span>
<el-tag v-if="value === 'Prepare'" class="status-label prepare">
{{ $t('test_track.plan.plan_status_prepare') }}
</el-tag>
<el-tag v-if="value === 'Underway'" class="status-label underway">
{{ $t('test_track.plan.plan_status_running') }}
</el-tag>
<el-tag v-if="value === 'Finished'" class="status-label finished">
{{ $t('test_track.plan.plan_status_finished') }}
</el-tag>
<el-tag v-if="value === 'Completed'" class="status-label completed">
{{ $t('test_track.plan.plan_status_completed') }}
</el-tag>
<el-tag v-if="value === 'Trash'" class="status-label trash">
{{ $t('test_track.plan.plan_status_trash') }}
</el-tag>
<el-tag v-if="value === 'Archived'" class="status-label archived">
{{ $t('test_track.plan.plan_status_archived') }}
</el-tag>
</span>
</template>
<script>
export default {
name: "BasicStatus",
components: {},
props: {
value: {
type: String
}
}
}
</script>
<style scoped>
.status-label {
height: 24px;
font-weight: 400;
font-size: 14px;
line-height: 22px;
padding: 1px 6px;
border-radius: 2px;
border-color: transparent;
}
.completed {
background-color: rgba(52, 199, 36, 0.2);
color: #34C724;
}
.underway {
background-color: rgba(120, 56, 135, 0.2);
color: #783887;
}
.prepare {
background-color: rgba(31, 35, 41, 0.1);
color: #646A73;
}
.finished {
background-color: rgba(0, 214, 185, 0.2);
color: #078372;
}
.trash {
background-color: rgba(245, 74, 69, 0.2);
color: #D83931;
}
.archived {
background-color: rgba(255, 136, 0, 0.2);
color: #DE7802;
}
</style>

View File

@ -0,0 +1,52 @@
<template>
<span>
<el-tag v-if="value === 'API_SCENARIO_TEST'" class="status-label api">
{{ $t('api_test.home_page.running_task_list.scenario_schedule') }}
</el-tag>
<el-tag v-if="value === 'TEST_PLAN_TEST'" class="status-label plan">
{{ $t('api_test.home_page.running_task_list.test_plan_schedule') }}
</el-tag>
<el-tag v-if="value === 'SWAGGER_IMPORT'" class="status-label swagger">
{{ $t('api_test.home_page.running_task_list.swagger_schedule') }}
</el-tag>
</span>
</template>
<script>
export default {
name: "BasicStatus",
components: {},
props: {
value: {
type: String
}
}
}
</script>
<style scoped>
.status-label {
height: 24px;
font-weight: 400;
font-size: 14px;
line-height: 22px;
padding: 1px 6px;
border-radius: 2px;
border-color: transparent;
}
.api {
background-color: rgba(52, 199, 36, 0.2);
color: #2EA121;
}
.swagger {
background-color: rgba(255, 136, 0, 0.2);
color: #DE7802;
}
.plan {
background-color: rgba(51, 112, 255, 0.2);
color: #245BDB;
}
</style>

View File

@ -19,6 +19,45 @@ const message = {
case_type: "Case Type", case_type: "Case Type",
test_plan: "Test Plan", test_plan: "Test Plan",
failure_times: "Failure times", failure_times: "Failure times",
},
rate: {
case_review: "Review rate",
case_review_pass: "Review pass rate",
cover: "Cover rate",
legacy: "Legacy rate",
legacy_issue: "Percentage of legacy defects",
},
dashboard: {
public: {
this_week: "This week ",
load_error: "Loading failure",
},
case_finished_review_pass_tip: "Reviewed cases/All reviewed cases *100%"
},
case_review_dashboard: {
case_count: "Case count",
not_review: "Not reviewed",
finished_review: "Reviewed",
not_pass: "Not pass",
pass: "Pass",
},
relevance_dashboard: {
api_case: "Api case",
scenario_case: "Scenario case",
performance_case: "Performance case",
relevance_case_count: "Relevance case count",
not_cover: "Not cover",
cover: "Cover",
},
bug_dashboard: {
un_closed_bug_count: "Unclosed bug count",
un_closed_range: "Unclosed bug range",
un_closed_range_tips: "Unclosed bugs/all associated bugs *100%",
un_closed_bug_case_range: "Unclosed bug case range",
un_closed_bug_case_range_tips: "Unclosed bugs/all associated cases *100%",
un_closed_count: "Unclosed bug count",
total_count: "Bug total",
case_count: "Case count",
} }
}, },
plan: { plan: {

View File

@ -19,6 +19,45 @@ const message = {
case_type: "用例类型", case_type: "用例类型",
test_plan: "所属测试计划", test_plan: "所属测试计划",
failure_times: "失败次数", failure_times: "失败次数",
},
rate: {
case_review: "评审率",
case_review_pass: "评审通过率",
cover: "覆盖率",
legacy: "遗留率",
legacy_issue: "遗留缺陷占比",
},
dashboard: {
public: {
this_week: "本周",
load_error: "加载失败",
},
case_finished_review_pass_tip: "已评审通过的案例/所有完成评审的案例*100%"
},
case_review_dashboard: {
case_count: "用例数量",
not_review: "未评审",
finished_review: "已评审",
not_pass: "未通过",
pass: "已通过",
},
relevance_dashboard: {
api_case: "接口用例",
scenario_case: "场景用例",
performance_case: "性能用例",
relevance_case_count: "关联用例数量",
not_cover: "未覆盖",
cover: "已覆盖",
},
bug_dashboard: {
un_closed_bug_count: "遗留缺陷",
un_closed_range: "遗留率",
un_closed_range_tips: "未关闭缺陷/所有关联的缺陷*100%",
un_closed_bug_case_range: "遗留缺陷占比",
un_closed_bug_case_range_tips: "未关闭缺陷/所有关联的用例*100%",
un_closed_count: "遗留缺陷数",
total_count: "缺陷总数",
case_count: "用例总数",
} }
}, },
plan: { plan: {

View File

@ -19,6 +19,45 @@ const message = {
case_type: "用例類型", case_type: "用例類型",
test_plan: "所屬測試計劃", test_plan: "所屬測試計劃",
failure_times: "失敗次數", failure_times: "失敗次數",
},
rate: {
case_review: "評審率",
case_review_pass: "評審通過率",
cover: "覆蓋率",
legacy: "遺留率",
legacy_issue: "遺留缺陷佔比",
},
dashboard: {
public: {
this_week: "本週",
load_error: "加載失敗",
},
case_finished_review_pass_tip: "已評審通過的案例/所有完成評審的案例*100%"
},
case_review_dashboard: {
case_count: "用例數量",
not_review: "未評審",
finished_review: "已評審",
not_pass: "未通過",
pass: "已通過",
},
relevance_dashboard: {
api_case: "接口用例",
scenario_case: "場景用例",
performance_case: "性能用例",
relevance_case_count: "關聯用例數量",
not_cover: "未覆蓋",
cover: "已覆蓋",
},
bug_dashboard: {
un_closed_bug_count: "遺留缺陷",
un_closed_range: "遺留率",
un_closed_range_tips: "未關閉缺陷/所有關聯的缺陷*100%",
un_closed_bug_case_range: "遺留缺陷佔比",
un_closed_bug_case_range_tips: "未關閉缺陷/所有關聯的用例*100%",
un_closed_count: "遺留缺陷數",
total_count: "缺陷總數",
case_count: "用例總數",
} }
}, },
plan: { plan: {