refactor(测试跟踪): 优化测试跟踪首页跳转及缺陷遗留面板

--story=1010425 --user=宋昌昌 【测试跟踪】测试跟踪首页交互升级 https://www.tapd.cn/55049933/s/1296708
This commit is contained in:
song-cc-rock 2022-11-16 20:57:26 +08:00
parent 784c1ce67c
commit 1af5e68bbb
18 changed files with 161 additions and 124 deletions

View File

@ -466,7 +466,7 @@ export default {
status_active: '激活',
status_delete: '删除',
status_in_progress: '接受/处理',
status_rejected: '拒绝',
status_rejected: '拒绝',
status_upcoming: '待办',
status_reopened: '重新打开',
please_choose_current_owner: "请选择处理人",

View File

@ -466,7 +466,7 @@ export default {
status_active: '激活',
status_delete: '刪除',
status_in_progress: '接受/處理',
status_rejected: '拒絕',
status_rejected: '拒絕',
status_upcoming: '待辦',
status_reopened: '重新打開',
please_choose_current_owner: "請選擇處理人",

View File

@ -64,4 +64,13 @@ public class IssuesRequest extends BaseQueryRequest {
* 缺陷导出勾选ID
*/
private List<String> exportIds;
/**
* 本周遗留缺陷
*/
private Boolean thisWeekUnClosedIssue = false;
/**
* 本周遗留缺陷ID
*/
private List<String> thisWeekUncloseIds;
}

View File

@ -44,4 +44,8 @@ public interface ExtIssuesMapper {
List<IssuesDao> getIssueCustomFields(List<String> ids);
List<IssuesDao> getPlatformIssueByIds(@Param("ids") List<String> ids, @Param("projectId") String projectId);
Long getThisWeekIssueCount(@Param("ids") List<String> ids, @Param("projectId") String projectId);
List<String> getTestPlanThisWeekIssue(String projectId);
}

View File

@ -161,6 +161,24 @@
#{value}
</foreach>
</select>
<select id="getThisWeekIssueCount" resultType="java.lang.Long">
select count(*) from issues where project_id = #{projectId} and date_sub(curdate(), interval 7 day) &lt;= from_unixtime(round(create_time / 1000, 0)) and id in
<foreach collection="ids" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</select>
<select id="getTestPlanThisWeekIssue" resultType="java.lang.String">
select distinct tci.issues_id
from test_plan_test_case tptc
join test_plan tp on tp.id = tptc.plan_id
join test_case_issues tci on tptc.id = tci.resource_id
join issues on tci.issues_id = issues.id
where tptc.is_del != 1 and date_sub(curdate(), interval 7 day) &lt;= from_unixtime(round(issues.create_time / 1000, 0))
and tp.project_id = #{projectId}
</select>
<select id="getIssueCustomFields" resultType="io.metersphere.xpack.track.dto.IssuesDao">
select cfi.field_id as fieldId,
cf.type fieldType,
@ -229,6 +247,12 @@
#{value}
</foreach>
</if>
<if test="request.thisWeekUnClosedIssue and request.thisWeekUncloseIds != null and request.thisWeekUncloseIds.size() > 0">
and issues.id in
<foreach collection="request.thisWeekUncloseIds" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</if>
<if test="!request.selectAll and request.exportIds != null and request.exportIds.size > 0">
and issues.id in
<foreach collection="request.exportIds" item="value" separator="," open="(" close=")">

View File

@ -48,6 +48,9 @@ public class IssuesController {
@PostMapping("/list/{goPage}/{pageSize}")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_ISSUE_READ)
public Pager<List<IssuesDao>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody IssuesRequest request) {
if (request.getThisWeekUnClosedIssue()) {
issuesService.setThisWeekUnclosedIds(request);
}
Page<List<Issues>> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, issuesService.list(request));
}

View File

@ -13,10 +13,11 @@ public class BugStatistics {
private long bugUnclosedCount;
private long bugTotalCount;
private long caseTotalCount;
private long unClosedP0Size;
private long unClosedP1Size;
private long unClosedP2Size;
private long unClosedP3Size;
private long newCount;
private long resolvedCount;
private long rejectedCount;
private long unKnownCount;
private long thisWeekCount;
private String unClosedRage;
private String bugCaseRage;
private List<TestPlanBugCount> list = new ArrayList<>();

View File

@ -1455,4 +1455,17 @@ public class IssuesService {
updateIssues(issue);
});
}
public void setThisWeekUnclosedIds(IssuesRequest request) {
List<String> issueIds = extIssuesMapper.getTestPlanThisWeekIssue(request.getProjectId());
Map<String, String> statusMap = customFieldIssuesService.getIssueStatusMap(issueIds, request.getProjectId());
if (MapUtils.isEmpty(statusMap)) {
request.setThisWeekUncloseIds(issueIds);
} else {
List<String> unClosedIds = issueIds.stream()
.filter(id -> !StringUtils.equals(statusMap.getOrDefault(id, StringUtils.EMPTY).replaceAll("\"", StringUtils.EMPTY), "closed"))
.collect(Collectors.toList());
request.setThisWeekUncloseIds(unClosedIds);
}
}
}

View File

@ -118,19 +118,20 @@ public class TrackService {
int index = 1;
int totalUnClosedPlanBugSize = 0;
int totalPlanBugSize = 0;
int totalCaseSize = 0;
int unClosedP0Size = 0;
int unClosedP1Size = 0;
int unClosedP2Size = 0;
int unClosedP3Size = 0;
int newCount = 0;
int resolvedCount = 0;
int rejectedCount = 0;
int unKnownCount = 0;
int thisWeekCount = 0;
for (TestPlan plan : plans) {
Map<String, Integer> bugSizeMap = getPlanBugSize(plan.getId(), projectId);
int planBugSize = bugSizeMap.get("total");
int unClosedPlanBugSize = bugSizeMap.get("unClosed");
unClosedP0Size += bugSizeMap.get("p0Size");
unClosedP1Size += bugSizeMap.get("p1Size");
unClosedP2Size += bugSizeMap.get("p2Size");
unClosedP3Size += bugSizeMap.get("p3Size");
newCount += bugSizeMap.get("newCount");
resolvedCount += bugSizeMap.get("resolvedCount");
rejectedCount += bugSizeMap.get("rejectedCount");
unKnownCount += bugSizeMap.get("unKnownCount");
thisWeekCount += bugSizeMap.get("thisWeekCount");
totalUnClosedPlanBugSize += unClosedPlanBugSize;
totalPlanBugSize += planBugSize;
// bug为0不记录
@ -144,32 +145,25 @@ public class TrackService {
testPlanBug.setCreateTime(plan.getCreateTime());
testPlanBug.setStatus(plan.getStatus());
testPlanBug.setPlanId(plan.getId());
int planCaseSize = getPlanCaseSize(plan.getId());
totalCaseSize += planCaseSize;
testPlanBug.setCaseSize(planCaseSize);
testPlanBug.setCaseSize(getPlanCaseSize(plan.getId()));
testPlanBug.setBugSize(unClosedPlanBugSize);
double planPassRage = getPlanPassRage(plan.getId());
testPlanBug.setPassRage(planPassRage + "%");
list.add(testPlanBug);
}
bugStatistics.setList(list);
bugStatistics.setBugUnclosedCount(totalUnClosedPlanBugSize);
bugStatistics.setBugTotalCount(totalPlanBugSize);
bugStatistics.setCaseTotalCount(totalCaseSize);
float rage = totalPlanBugSize == 0 ? 0 : (float) totalUnClosedPlanBugSize * 100 / totalPlanBugSize;
DecimalFormat df = new DecimalFormat("0.0");
bugStatistics.setUnClosedRage(df.format(rage) + "%");
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);
bugStatistics.setNewCount(newCount);
bugStatistics.setResolvedCount(resolvedCount);
bugStatistics.setRejectedCount(rejectedCount);
bugStatistics.setUnKnownCount(unKnownCount);
bugStatistics.setThisWeekCount(thisWeekCount);
return bugStatistics;
}
@ -180,18 +174,16 @@ public class TrackService {
private Map<String, Integer> getPlanBugSize(String planId, String projectId) {
List<String> issueIds = extTestCaseMapper.getTestPlanBug(planId);
Map<String, String> statusMap = customFieldIssuesService.getIssueStatusMap(issueIds, projectId);
Map<String, String> degreeMap = customFieldIssuesService.getIssueDegreeMap(issueIds, projectId);
Map<String, Integer> bugSizeMap = new HashMap<>();
bugSizeMap.put("total", issueIds.size());
// 缺陷是否有状态
List<String> unClosedIds = new ArrayList<>();
List<String> unClosedIds;
if (MapUtils.isEmpty(statusMap)) {
unClosedIds = issueIds;
bugSizeMap.put("unClosed", issueIds.size());
bugSizeMap.put("newCount", issueIds.size());
} else {
unClosedIds = issueIds.stream()
.filter(id -> !StringUtils.equals(statusMap.getOrDefault(id, StringUtils.EMPTY).replaceAll("\"", StringUtils.EMPTY), "closed"))
@ -199,34 +191,33 @@ public class TrackService {
bugSizeMap.put("unClosed", unClosedIds.size());
}
// 如果没有严重程度字段
int p0Size = 0;
int p1Size = 0;
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;
int thisWeekCount = 0;
if (CollectionUtils.isNotEmpty(unClosedIds)) {
thisWeekCount = extIssuesMapper.getThisWeekIssueCount(unClosedIds, projectId).intValue();
}
bugSizeMap.put("thisWeekCount", thisWeekCount);
// 如果没有严重程度字段
int newCount = 0;
int resolvedCount = 0;
int rejectedCount = 0;
int unKnownCount = 0;
for (String unClosedId : unClosedIds) {
String status = statusMap.getOrDefault(unClosedId, StringUtils.EMPTY).replaceAll("\"", StringUtils.EMPTY);
if (StringUtils.equalsIgnoreCase(status, "new")) {
newCount += 1;
} else if (StringUtils.equalsIgnoreCase(status, "resolved")) {
resolvedCount += 1;
} else if (StringUtils.equalsIgnoreCase(status, "rejected")) {
rejectedCount += 1;
} else {
unKnownCount += 1;
}
}
bugSizeMap.put("p0Size", p0Size);
bugSizeMap.put("p1Size", p1Size);
bugSizeMap.put("p2Size", p2Size);
bugSizeMap.put("p3Size", p3Size);
bugSizeMap.put("newCount", newCount);
bugSizeMap.put("resolvedCount", resolvedCount);
bugSizeMap.put("rejectedCount", rejectedCount);
bugSizeMap.put("unKnownCount", unKnownCount);
return bugSizeMap;
}

View File

@ -89,12 +89,13 @@ export default {
let home;
switch (page) {
case "testCase":
this.$router.push({
path: '/track/case/all/' + uuid + '/' + dataType + '/' + selectType
home = this.$router.resolve({
name: 'testCaseRedirect',
params: {redirectID: uuid, dataType: dataType, dataSelectRange: selectType}
})
break;
case "testPlanEdit":
this.$router.push('/track/plan/view/' + selectType)
home = this.$router.resolve('/track/plan/view/' + selectType)
break;
case "scenarioWithQuery":
home = this.$router.resolve('/api/automation/' + uuid + "/" + dataType + "/" + selectType);

View File

@ -83,10 +83,11 @@ export default {
bugUnclosedCount: 0,
caseTotalCount: 0,
unClosedRage:" 0%",
unClosedP0Size: 0,
unClosedP1Size: 0,
unClosedP2Size: 0,
unClosedP3Size: 0,
newCount: 0,
resolvedCount: 0,
rejectedCount: 0,
unKnownCount: 0,
thisWeekCount: 0
},
}
},

View File

@ -15,7 +15,7 @@
<div v-show="!loadError">
<el-table :data="tableData" class="adjust-table table-content"
:header-cell-style="{backgroundColor: '#F5F6F7'}" max-height="224px">
<el-table-column prop="sortIndex" :label="$t('home.case.index')" show-overflow-tooltip/>
<el-table-column type="index" :label="$t('home.case.index')" show-overflow-tooltip/>
<el-table-column prop="caseName" :label="$t('home.case.case_name')">
<template v-slot:default="{row}">
<el-link type="info" @click="redirect(row.caseType,row.id)"

View File

@ -104,7 +104,10 @@ export default {
});
},
intoPlan(row) {
this.$router.push('/track/review/view/' + row.id);
let home = this.$router.resolve('/track/review/view/' + row.id);
if (home) {
window.open(home.href, '_blank');
}
},
searchMyCreator(data) {
if (data === 'true') {

View File

@ -11,35 +11,26 @@
<!-- 总数统计 -->
<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="ms-point-new"/>
<span class="count-title">{{ $t('test_track.issue.status_new') }}</span>
<span class="count-value">
{{ formatAmount(bugData.unClosedP3Size) }}
{{ formatAmount(bugData.newCount) }}
</span>
</div>
<div class="count-row">
<span class="ms-point-p2"/>
<span class="count-title">P2</span>
<span class="ms-point-resolved"/>
<span class="count-title">{{ $t('test_track.issue.status_resolved') }}</span>
<span class="count-value">
{{ formatAmount(bugData.unClosedP2Size) }}
{{ formatAmount(bugData.resolvedCount) }}
</span>
</div>
<div class="count-row">
<span class="ms-point-p1"/>
<span class="count-title">P1</span>
<span class="ms-point-rejected"/>
<span class="count-title">{{ $t('test_track.issue.status_rejected') }}</span>
<span class="count-value">
{{ formatAmount(bugData.unClosedP1Size) }}
{{ formatAmount(bugData.rejectedCount) }}
</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>
@ -49,6 +40,7 @@
import MsChart from "metersphere-frontend/src/components/chart/MsChart";
import {getUUID} from "metersphere-frontend/src/utils";
import {formatNumber} from "@/api/track";
import {getCurrentProjectID} from "@/business/utils/sdk-utils";
export default {
name: "CountChart",
@ -80,17 +72,14 @@ export default {
},
getTotal() {
let total = 0;
if (this.bugData.unClosedP0Size) {
total += this.bugData.unClosedP0Size;
if (this.bugData.newCount) {
total += this.bugData.newCount;
}
if (this.bugData.unClosedP1Size) {
total += this.bugData.unClosedP1Size;
if (this.bugData.resolvedCount) {
total += this.bugData.resolvedCount;
}
if (this.bugData.unClosedP2Size) {
total += this.bugData.unClosedP2Size;
}
if (this.bugData.unClosedP3Size) {
total += this.bugData.unClosedP3Size;
if (this.bugData.rejectedCount) {
total += this.bugData.rejectedCount;
}
return total;
},
@ -119,12 +108,11 @@ export default {
let protocolData = [{value: 0}];
let colorArr = ['#DEE0E3'];
if (this.getTotal() > 0) {
colorArr = ['#F54A45', '#FFD131', '#C1A9C8', '#10CECE',]
colorArr = ['#AA4FBF', '#14E1C6', '#FAD355',]
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'},
{value: this.bugData.newCount, name: this.$t('test_track.issue.status_new')},
{value: this.bugData.resolvedCount, name: this.$t('test_track.issue.status_resolved')},
{value: this.bugData.rejectedCount, name: this.$t('test_track.issue.status_rejected')},
];
}
let optionData = {
@ -134,7 +122,7 @@ export default {
},
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 + " >",
subtext: this.$t("home.dashboard.public.this_week") + ": +" + this.bugData.thisWeekCount + " >",
top: "center",
left: "center",
textStyle: {
@ -152,14 +140,14 @@ export default {
},
}
},
// sublink: "/#/track/case/all/" + getUUID() + "/case/thisWeekRelevanceCount",
// subtextStyle: {
// color: "#1F2329",
// fontSize: 12,
// width: 105,
// ellipsis: '... >',
// overflow: "truncate",
// },
sublink: "/#/track/issue/" + getUUID() + "/" + getCurrentProjectID() + "/thisWeekUnClosedIssue",
subtextStyle: {
color: "#1F2329",
fontSize: 12,
width: 105,
ellipsis: '... >',
overflow: "truncate",
},
itemGap: -60,
},
series: [
@ -208,35 +196,27 @@ export default {
font-weight: 500;
}
.ms-point-p3 {
.ms-point-rejected {
height: 8px;
width: 8px;
margin-right: 8px;
display: inline-block;
background-color: #F54A45;
background-color: #FAD355;
}
.ms-point-p2 {
.ms-point-resolved {
height: 8px;
width: 8px;
margin-right: 8px;
display: inline-block;
background-color: #FFD131;
background-color: #14E1C6;
}
.ms-point-p1 {
.ms-point-new {
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;
background-color: #AA4FBF;
}
</style>

View File

@ -267,7 +267,8 @@ export default {
userFilter: [],
isThirdPart: false,
creatorFilters: [],
loading: false
loading: false,
dataSelectRange: ""
};
},
watch: {
@ -276,6 +277,9 @@ export default {
},
},
activated() {
if (this.$route.params.dataSelectRange) {
this.dataSelectRange = this.$route.params.dataSelectRange;
}
this.page.result.loading = true;
this.$nextTick(() => {
//
@ -376,6 +380,9 @@ export default {
this.getIssues();
},
getIssues() {
if (this.dataSelectRange === 'thisWeekUnClosedIssue') {
this.page.condition.thisWeekUnClosedIssue = true;
}
this.page.condition.projectId = this.projectId;
this.page.condition.workspaceId= this.workspaceId;
this.page.condition.orders = getLastTableSortField(this.tableHeaderKey);

View File

@ -51,7 +51,7 @@ const message = {
cover: "已覆盖",
},
bug_dashboard: {
un_closed_bug_count: "遗留缺陷",
un_closed_bug_count: "遗留缺陷",
un_closed_range: "遗留率",
un_closed_range_tips: "未关闭缺陷/所有关联的缺陷*100%",
un_closed_bug_case_range: "遗留缺陷占比",

View File

@ -51,7 +51,7 @@ const message = {
cover: "已覆蓋",
},
bug_dashboard: {
un_closed_bug_count: "遺留缺陷",
un_closed_bug_count: "遺留缺陷",
un_closed_range: "遺留率",
un_closed_range_tips: "未關閉缺陷/所有關聯的缺陷*100%",
un_closed_bug_case_range: "遺留缺陷佔比",

View File

@ -37,7 +37,7 @@ export default {
component: () => import('@/business/report/TestPlanReport'),
},
{
path: 'issue/:id?/:projectId?',
path: 'issue/:id?/:projectId?/:dataSelectRange?',
name: 'issueManagement',
component: () => import('@/business/issue/IssueList.vue'),
},