feat( 报表统计): 报表统计从xpack挪到开源版,并增加保存、导出的权限。
报表统计从xpack挪到开源版,并增加保存、导出的权限。
This commit is contained in:
parent
6504298c63
commit
be6390d3bf
|
@ -0,0 +1,14 @@
|
|||
package io.metersphere.base.mapper.ext;
|
||||
|
||||
|
||||
import io.metersphere.reportstatistics.dto.TestAnalysisChartRequest;
|
||||
import io.metersphere.reportstatistics.dto.TestAnalysisChartResult;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ExtTestAnalysisMapper {
|
||||
|
||||
List<TestAnalysisChartResult> getCraeteCaseReport(TestAnalysisChartRequest request);
|
||||
|
||||
List<TestAnalysisChartResult> getUpdateCaseReport(TestAnalysisChartRequest request);
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="io.metersphere.base.mapper.ext.ExtTestAnalysisMapper">
|
||||
|
||||
<select id="getCraeteCaseReport" resultType="io.metersphere.reportstatistics.dto.TestAnalysisChartResult">
|
||||
select dateStr, ifnull(tt.num,0) countNum
|
||||
from
|
||||
(
|
||||
select adddate('2019-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) dateStr from
|
||||
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
|
||||
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
|
||||
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
|
||||
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
|
||||
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4
|
||||
) v
|
||||
left join
|
||||
(select FROM_UNIXTIME(t.create_time/1000, '%Y-%m-%d') as create_times,t.project_id,t.node_id,t.priority,count(id) num ,t.maintainer from test_case t
|
||||
WHERE project_id in
|
||||
<foreach collection="projects" item="id" separator="," open="(" close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
<if test="modules != null and modules.size() > 0">
|
||||
and node_id in
|
||||
<foreach collection="modules" item="id" separator="," open="(" close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="prioritys != null and prioritys.size() > 0">
|
||||
and priority in
|
||||
<foreach collection="prioritys" item="p" separator="," open="(" close=")">
|
||||
#{p}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="users != null and users.size() > 0">
|
||||
and maintainer in
|
||||
<foreach collection="users" item="p" separator="," open="(" close=")">
|
||||
#{p}
|
||||
</foreach>
|
||||
</if>
|
||||
GROUP BY create_times
|
||||
) tt
|
||||
on dateStr = tt.create_times
|
||||
where dateStr BETWEEN #{startTime} and #{endTime}
|
||||
<if test="order == null or order == ''">
|
||||
order by dateStr
|
||||
</if>
|
||||
<if test="order != null and order != ''">
|
||||
order by countNum ${order}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="getUpdateCaseReport" resultType="io.metersphere.reportstatistics.dto.TestAnalysisChartResult">
|
||||
select dateStr, ifnull(tt.num,0) countNum
|
||||
from
|
||||
(
|
||||
select adddate('2019-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) dateStr from
|
||||
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
|
||||
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
|
||||
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
|
||||
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
|
||||
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4
|
||||
) v
|
||||
left join
|
||||
(select FROM_UNIXTIME(t.update_time/1000, '%Y-%m-%d') as update_times,t.project_id,t.node_id,t.priority,t.create_time,t.update_time,count(id) num ,t.maintainer from test_case t
|
||||
WHERE create_time!= update_time
|
||||
and project_id in
|
||||
<foreach collection="projects" item="id" separator="," open="(" close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
<if test="modules != null and modules.size() > 0">
|
||||
and node_id in
|
||||
<foreach collection="modules" item="id" separator="," open="(" close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="prioritys != null and prioritys.size() > 0">
|
||||
and priority in
|
||||
<foreach collection="prioritys" item="id" separator="," open="(" close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="users != null and users.size() > 0">
|
||||
and maintainer in
|
||||
<foreach collection="users" item="p" separator="," open="(" close=")">
|
||||
#{p}
|
||||
</foreach>
|
||||
</if>
|
||||
GROUP BY update_times
|
||||
) tt
|
||||
on dateStr = tt.update_times
|
||||
where dateStr BETWEEN #{startTime} and #{endTime}
|
||||
<if test="order == null or order == ''">
|
||||
order by dateStr
|
||||
</if>
|
||||
<if test="order != null and order != ''">
|
||||
order by countNum ${order}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,65 @@
|
|||
package io.metersphere.base.mapper.ext;
|
||||
|
||||
import io.metersphere.reportstatistics.dto.TestCaseCountChartResult;
|
||||
import io.metersphere.reportstatistics.dto.TestCaseCountRequest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ExtTestCaseCountMapper {
|
||||
|
||||
/**
|
||||
* 创建人 维护人 用例类型 用例状态 用例等级
|
||||
*
|
||||
* create_user
|
||||
* maintainer
|
||||
* '功能用例'
|
||||
* status
|
||||
* priority
|
||||
*
|
||||
* @ request
|
||||
* @return
|
||||
*/
|
||||
List<TestCaseCountChartResult> getFunctionCaseCount(TestCaseCountRequest request);
|
||||
|
||||
/**
|
||||
* 创建人 维护人 用例类型 用例状态 用例等级
|
||||
*
|
||||
* create_user_id
|
||||
* ----不知道
|
||||
* '接口用例'
|
||||
* status
|
||||
* ----不知道
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
List<TestCaseCountChartResult> getApiCaseCount(TestCaseCountRequest request);
|
||||
|
||||
/**
|
||||
* 创建人 维护人 用例类型 用例状态 用例等级
|
||||
*
|
||||
* create_user
|
||||
* principal
|
||||
* '场景用例'
|
||||
* status
|
||||
* level
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
List<TestCaseCountChartResult> getScenarioCaseCount(TestCaseCountRequest request);
|
||||
|
||||
/**
|
||||
* 创建人 维护人 用例类型 用例状态 用例等级
|
||||
*
|
||||
* create_user
|
||||
* follow_people
|
||||
* '性能用例'
|
||||
* status
|
||||
* 不知道
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
List<TestCaseCountChartResult> getLoadCaseCount(TestCaseCountRequest request);
|
||||
}
|
|
@ -0,0 +1,219 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="io.metersphere.base.mapper.ext.ExtTestCaseCountMapper">
|
||||
|
||||
<select id="getFunctionCaseCount" resultType="io.metersphere.reportstatistics.dto.TestCaseCountChartResult">
|
||||
select
|
||||
<if test="testCaseGroupColumn != null and testCaseGroupColumn != ''">
|
||||
${testCaseGroupColumn} AS groupName,
|
||||
</if>
|
||||
count(id) AS countNum
|
||||
FROM test_case
|
||||
<where>
|
||||
project_id = #{projectId}
|
||||
AND `status` != 'Trash'
|
||||
<if test="startTime > 0">
|
||||
AND create_time >= #{startTime}
|
||||
</if>
|
||||
<if test="endTime > 0">
|
||||
AND create_time <= #{endTime}
|
||||
</if>
|
||||
<if test="filterSearchList != null and filterSearchList.size() > 0">
|
||||
AND
|
||||
<trim prefix="(" prefixOverrides="AND|OR" suffix=")">
|
||||
<foreach collection="filterSearchList.entrySet()" index="key" item="values">
|
||||
<if test="values != null and values.size() > 0">
|
||||
<choose>
|
||||
<when test="key=='caselevel'">
|
||||
${filterType} priority in
|
||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
</when>
|
||||
<when test="key=='creator'">
|
||||
${filterType} create_user in
|
||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
</when>
|
||||
<when test="key=='maintainer'">
|
||||
${filterType} maintainer in
|
||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
</when>
|
||||
<when test="key=='casestatus'">
|
||||
${filterType} UPPER(status) in
|
||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
</when>
|
||||
</choose>
|
||||
</if>
|
||||
</foreach>
|
||||
</trim>
|
||||
</if>
|
||||
</where>
|
||||
<if test="testCaseGroupColumn != null and testCaseGroupColumn != ''">
|
||||
GROUP BY ${testCaseGroupColumn}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="getApiCaseCount" resultType="io.metersphere.reportstatistics.dto.TestCaseCountChartResult">
|
||||
select
|
||||
<if test="testCaseGroupColumn != null and testCaseGroupColumn != ''">
|
||||
${apiCaseGroupColumn} AS groupName,
|
||||
</if>
|
||||
count(id) AS countNum
|
||||
FROM api_test_case
|
||||
<where>
|
||||
project_id = #{projectId}
|
||||
AND `status` != 'Trash'
|
||||
<if test="startTime > 0">
|
||||
AND (create_time >= #{startTime})
|
||||
</if>
|
||||
<if test="endTime > 0">
|
||||
AND ( create_time <= #{endTime})
|
||||
</if>
|
||||
<if test="apiFilterSearchList != null and apiFilterSearchList.size() > 0">
|
||||
AND
|
||||
<trim prefix="(" prefixOverrides="AND|OR" suffix=")">
|
||||
<foreach collection="apiFilterSearchList.entrySet()" index="key" item="values">
|
||||
<if test="values != null and values.size() > 0">
|
||||
<choose>
|
||||
<when test="key=='caselevel'">
|
||||
${filterType} priority in
|
||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
</when>
|
||||
<when test="key=='creator'">
|
||||
${filterType} create_user_id in
|
||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
</when>
|
||||
<when test="key=='casestatus'">
|
||||
${filterType}
|
||||
(UPPER(status) in
|
||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
<if test="values.contains('RUNNING')">
|
||||
OR status IS NULL
|
||||
</if>
|
||||
)
|
||||
</when>
|
||||
</choose>
|
||||
</if>
|
||||
</foreach>
|
||||
</trim>
|
||||
</if>
|
||||
</where>
|
||||
<if test="testCaseGroupColumn != null and testCaseGroupColumn != ''">
|
||||
GROUP BY ${apiCaseGroupColumn}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="getScenarioCaseCount" resultType="io.metersphere.reportstatistics.dto.TestCaseCountChartResult">
|
||||
select
|
||||
<if test="testCaseGroupColumn != null and testCaseGroupColumn != ''">
|
||||
${scenarioCaseGroupColumn} AS groupName,
|
||||
</if>
|
||||
count(id) AS countNum
|
||||
FROM api_scenario
|
||||
<where>
|
||||
project_id = #{projectId}
|
||||
AND `status` != 'Trash'
|
||||
<if test="startTime > 0">
|
||||
AND (create_time >= #{startTime})
|
||||
</if>
|
||||
<if test="endTime > 0">
|
||||
AND ( create_time <= #{endTime})
|
||||
</if>
|
||||
<if test="filterSearchList != null and filterSearchList.size() > 0">
|
||||
AND
|
||||
<trim prefix="(" prefixOverrides="AND|OR" suffix=")">
|
||||
<foreach collection="filterSearchList.entrySet()" index="key" item="values">
|
||||
<if test="values != null and values.size() > 0">
|
||||
<choose>
|
||||
<when test="key=='caselevel'">
|
||||
${filterType} level in
|
||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
</when>
|
||||
<when test="key=='creator'">
|
||||
${filterType} create_user in
|
||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
</when>
|
||||
<when test="key=='maintainer'">
|
||||
${filterType} principal in
|
||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
</when>
|
||||
<when test="key=='casestatus'">
|
||||
${filterType} UPPER(status) in
|
||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
</when>
|
||||
</choose>
|
||||
</if>
|
||||
</foreach>
|
||||
</trim>
|
||||
</if>
|
||||
</where>
|
||||
<if test="testCaseGroupColumn != null and testCaseGroupColumn != ''">
|
||||
GROUP BY ${scenarioCaseGroupColumn}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="getLoadCaseCount" resultType="io.metersphere.reportstatistics.dto.TestCaseCountChartResult">
|
||||
select
|
||||
<if test="testCaseGroupColumn != null and testCaseGroupColumn != ''">
|
||||
${loadCaseGroupColumn} AS groupName,
|
||||
</if>
|
||||
count(id) AS countNum
|
||||
FROM load_test
|
||||
<where>
|
||||
project_id = #{projectId}
|
||||
<if test="startTime > 0">
|
||||
AND (create_time >= #{startTime})
|
||||
</if>
|
||||
<if test="endTime > 0">
|
||||
AND ( create_time <= #{endTime})
|
||||
</if>
|
||||
<if test="loadFilterSearchList != null and loadFilterSearchList.size() > 0">
|
||||
AND
|
||||
<trim prefix="(" prefixOverrides="AND|OR" suffix=")">
|
||||
<foreach collection="loadFilterSearchList.entrySet()" index="key" item="values">
|
||||
<if test="values != null and values.size() > 0">
|
||||
<choose>
|
||||
<when test="key=='creator'">
|
||||
${filterType} create_user in
|
||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
</when>
|
||||
<when test="key=='casestatus'">
|
||||
${filterType} UPPER(status) in
|
||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
</when>
|
||||
</choose>
|
||||
</if>
|
||||
</foreach>
|
||||
</trim>
|
||||
</if>
|
||||
</where>
|
||||
<if test="testCaseGroupColumn != null and testCaseGroupColumn != ''">
|
||||
GROUP BY ${loadCaseGroupColumn}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,56 @@
|
|||
package io.metersphere.reportstatistics.controller;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import io.metersphere.base.domain.ReportStatistics;
|
||||
import io.metersphere.base.domain.ReportStatisticsWithBLOBs;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.reportstatistics.dto.ReportStatisticsSaveRequest;
|
||||
import io.metersphere.reportstatistics.service.ReportStatisticsService;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author song.tianyang
|
||||
* @Date 2021/9/14 2:58 下午
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = "/history/report")
|
||||
public class HistoryReportController {
|
||||
|
||||
@Resource
|
||||
private ReportStatisticsService reportStatisticsService;
|
||||
|
||||
@PostMapping("/selectByParams")
|
||||
public List<ReportStatistics> selectByParams(@RequestBody ReportStatisticsSaveRequest request) {
|
||||
List<ReportStatistics> returnList = reportStatisticsService.selectByProjectIdAndReportType(request.getProjectId(),request.getReportType());
|
||||
LogUtil.info("报表查询结果:"+JSONArray.toJSONString(returnList));
|
||||
return returnList;
|
||||
}
|
||||
|
||||
@PostMapping("/saveReport")
|
||||
public ReportStatisticsWithBLOBs saveReport(@RequestBody ReportStatisticsSaveRequest request){
|
||||
ReportStatisticsWithBLOBs returnData = reportStatisticsService.saveByRequest(request);
|
||||
return returnData;
|
||||
}
|
||||
|
||||
@PostMapping("/updateReport")
|
||||
public ReportStatisticsWithBLOBs updateReport(@RequestBody ReportStatisticsSaveRequest request){
|
||||
ReportStatisticsWithBLOBs returnData = reportStatisticsService.updateByRequest(request);
|
||||
return returnData;
|
||||
}
|
||||
|
||||
@PostMapping("/deleteByParam")
|
||||
public int deleteById(@RequestBody ReportStatisticsSaveRequest request) {
|
||||
return reportStatisticsService.deleteById(request.getId());
|
||||
}
|
||||
|
||||
@PostMapping("/selectById")
|
||||
public ReportStatisticsWithBLOBs selectById(@RequestBody ReportStatisticsSaveRequest request) {
|
||||
return reportStatisticsService.selectById(request.getId());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package io.metersphere.reportstatistics.controller;
|
||||
|
||||
import io.metersphere.reportstatistics.dto.TestAnalysisChartRequest;
|
||||
import io.metersphere.reportstatistics.dto.TestAnalysisResult;
|
||||
import io.metersphere.reportstatistics.service.TestAnalysisService;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = "/report/test/analysis")
|
||||
public class TestAnalysisController {
|
||||
|
||||
@Resource
|
||||
TestAnalysisService testAnalysisService;
|
||||
|
||||
@PostMapping("/getReport")
|
||||
public TestAnalysisResult getReport(@RequestBody TestAnalysisChartRequest request) {
|
||||
return testAnalysisService.getReport(request);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package io.metersphere.reportstatistics.controller;
|
||||
|
||||
import io.metersphere.reportstatistics.dto.TestCaseCountRequest;
|
||||
import io.metersphere.reportstatistics.dto.TestCaseCountResponse;
|
||||
import io.metersphere.reportstatistics.service.TestCaseCountService;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = "/report/test/case/count")
|
||||
public class TestCaseCountController {
|
||||
|
||||
@Resource
|
||||
TestCaseCountService testCaseCountService;
|
||||
|
||||
@PostMapping("/initDatas")
|
||||
public Map<String, List<Map<String,String>>> initDatas(@RequestBody TestCaseCountRequest request) {
|
||||
Map<String,List<Map<String, String>>> returnMap = testCaseCountService.getSelectFilterDatas(request.getProjectId());
|
||||
|
||||
return returnMap;
|
||||
}
|
||||
|
||||
@PostMapping("/getReport")
|
||||
public TestCaseCountResponse getReport(@RequestBody TestCaseCountRequest request) {
|
||||
TestCaseCountResponse response = testCaseCountService.getReport(request);
|
||||
return response;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package io.metersphere.reportstatistics.dto;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.metersphere.reportstatistics.dto.charts.Series;
|
||||
import io.metersphere.reportstatistics.dto.charts.Title;
|
||||
import io.metersphere.reportstatistics.dto.charts.XAxis;
|
||||
import io.metersphere.reportstatistics.dto.charts.YAxis;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class PieChartDTO {
|
||||
private JSONObject dataset;
|
||||
private JSONObject tooltip;
|
||||
private XAxis xAxis;
|
||||
private YAxis yAxis;
|
||||
private List<Series> series;
|
||||
private List<Title> title;
|
||||
private int width;
|
||||
|
||||
public PieChartDTO() {
|
||||
tooltip = new JSONObject();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package io.metersphere.reportstatistics.dto;
|
||||
|
||||
import io.metersphere.base.domain.ReportStatisticsWithBLOBs;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author song.tianyang
|
||||
* @Date 2021/9/14 4:51 下午
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class ReportStatisticsSaveRequest extends ReportStatisticsWithBLOBs {
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package io.metersphere.reportstatistics.dto;
|
||||
|
||||
public enum ReportStatisticsType {
|
||||
TEST_CASE_COUNT,TEST_CASE_ANALYSIS
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package io.metersphere.reportstatistics.dto;
|
||||
|
||||
import io.metersphere.reportstatistics.dto.charts.Legend;
|
||||
import io.metersphere.reportstatistics.dto.charts.Series;
|
||||
import io.metersphere.reportstatistics.dto.charts.XAxis;
|
||||
import io.metersphere.reportstatistics.dto.charts.YAxis;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestAnalysisChartDTO {
|
||||
private Legend legend;
|
||||
private XAxis xAxis;
|
||||
private YAxis yAxis;
|
||||
private List<Series> series;
|
||||
|
||||
public TestAnalysisChartDTO() {
|
||||
}
|
||||
|
||||
public TestAnalysisChartDTO(Legend legend, XAxis xAxis, YAxis yAxis, List<Series> series) {
|
||||
this.legend = legend;
|
||||
this.xAxis = xAxis;
|
||||
this.yAxis = yAxis;
|
||||
this.series = series;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package io.metersphere.reportstatistics.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestAnalysisChartRequest {
|
||||
private boolean createCase;
|
||||
private boolean updateCase;
|
||||
private String order;
|
||||
private List<Long> times;
|
||||
private String startTime;
|
||||
private String endTime;
|
||||
private List<String> prioritys;
|
||||
private List<String> projects;
|
||||
private List<String> modules;
|
||||
private List<String> users;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package io.metersphere.reportstatistics.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestAnalysisChartResult {
|
||||
private String dateStr;
|
||||
private String countNum;
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package io.metersphere.reportstatistics.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestAnalysisResult {
|
||||
private TestAnalysisChartDTO chartDTO;
|
||||
private List<TestAnalysisTableDTO> tableDTOs;
|
||||
|
||||
public TestAnalysisResult() {
|
||||
|
||||
}
|
||||
|
||||
public TestAnalysisResult(TestAnalysisChartDTO chartDTO, List<TestAnalysisTableDTO> tableDTOs) {
|
||||
this.chartDTO = chartDTO;
|
||||
this.tableDTOs = tableDTOs;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package io.metersphere.reportstatistics.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestAnalysisTableDTO {
|
||||
private String id;
|
||||
private String name;
|
||||
private String createCount;
|
||||
private String updateCount;
|
||||
private List<TestAnalysisTableDTO> children;
|
||||
|
||||
public TestAnalysisTableDTO() {
|
||||
|
||||
}
|
||||
|
||||
public TestAnalysisTableDTO(String name, String createCount, String updateCount, List<TestAnalysisTableDTO> children) {
|
||||
this.id = UUID.randomUUID().toString();
|
||||
this.name = name;
|
||||
this.createCount = createCount;
|
||||
this.updateCount = updateCount;
|
||||
this.children = children;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package io.metersphere.reportstatistics.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestCaseCountChartResult {
|
||||
private String groupName;
|
||||
private long countNum;
|
||||
|
||||
public String getCountNumStr(){
|
||||
return String.valueOf(countNum);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package io.metersphere.reportstatistics.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestCaseCountRequest {
|
||||
//x轴字段
|
||||
private String xaxis;
|
||||
//y轴字段
|
||||
private List<String> yaxis;
|
||||
|
||||
//搜索条件
|
||||
private String projectId;
|
||||
private String timeType;
|
||||
private TimeFilter timeFilter;
|
||||
private List<Long> times;
|
||||
private String order;
|
||||
|
||||
//起始时间
|
||||
private long startTime = 0;
|
||||
//结束时间
|
||||
private long endTime = 0;
|
||||
|
||||
//其余条件
|
||||
private String filterType;
|
||||
private List<Map<String,Object>> filters;
|
||||
|
||||
/**
|
||||
* 功能用例、接口用例、场景用例、性能用例的分组字段
|
||||
*/
|
||||
private String testCaseGroupColumn;
|
||||
private String apiCaseGroupColumn;
|
||||
private String scenarioCaseGroupColumn;
|
||||
private String loadCaseGroupColumn;
|
||||
|
||||
/**
|
||||
* filter整理后的查询数据
|
||||
* @return
|
||||
*/
|
||||
private Map<String,List<String>> filterSearchList;
|
||||
private Map<String,List<String>> apiFilterSearchList;
|
||||
private Map<String,List<String>> loadFilterSearchList;
|
||||
|
||||
public int getTimeRange(){
|
||||
if(timeFilter != null){
|
||||
return timeFilter.getTimeRange();
|
||||
}else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public String getTimeRangeUnit(){
|
||||
if(timeFilter != null){
|
||||
return timeFilter.getTimeRangeUnit();
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setFilterSearchList(String key,List<String> values){
|
||||
if(this.filterSearchList == null){
|
||||
this.filterSearchList = new HashMap<>();
|
||||
}
|
||||
filterSearchList.put(key,values);
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
class TimeFilter{
|
||||
private int timeRange;
|
||||
private String timeRangeUnit;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package io.metersphere.reportstatistics.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestCaseCountResponse {
|
||||
private TestAnalysisChartDTO barChartDTO;
|
||||
private PieChartDTO pieChartDTO;
|
||||
private List<TestCaseCountTableDTO> tableDTOs;
|
||||
|
||||
public TestCaseCountResponse() {
|
||||
|
||||
}
|
||||
|
||||
public TestCaseCountResponse(TestAnalysisChartDTO chartDTO, PieChartDTO pieChartDTO, List<TestCaseCountTableDTO> tableDTOs) {
|
||||
this.pieChartDTO = pieChartDTO;
|
||||
this.barChartDTO = chartDTO;
|
||||
this.tableDTOs = tableDTOs;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package io.metersphere.reportstatistics.dto;
|
||||
|
||||
/**
|
||||
* @author song.tianyang
|
||||
* @Date 2021/9/8 5:36 下午
|
||||
*/
|
||||
public class TestCaseCountSummary {
|
||||
public String groupName;
|
||||
|
||||
public long testCaseCount = 0;
|
||||
public long apiCaseCount = 0;
|
||||
public long scenarioCaseCount = 0;
|
||||
public long loadCaseCount = 0;
|
||||
|
||||
public TestCaseCountSummary(String groupName) {
|
||||
this.groupName = groupName;
|
||||
}
|
||||
|
||||
public long getAllCount() {
|
||||
return this.testCaseCount + this.apiCaseCount + this.scenarioCaseCount + this.loadCaseCount;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package io.metersphere.reportstatistics.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestCaseCountTableDTO {
|
||||
private String id;
|
||||
private String name;
|
||||
private String allCount;
|
||||
private String testCaseCount;
|
||||
private String apiCaseCount;
|
||||
private String scenarioCaseCount;
|
||||
private String loadCaseCount;
|
||||
|
||||
private List<TestCaseCountTableDTO> children;
|
||||
|
||||
public TestCaseCountTableDTO(String name, long testCaseCount, long apiCaseCount, long scenarioCaseCount, long loadCaseCount) {
|
||||
this.id = UUID.randomUUID().toString();
|
||||
this.name = name;
|
||||
this.testCaseCount = String.valueOf(testCaseCount);
|
||||
this.apiCaseCount = String.valueOf(apiCaseCount);
|
||||
this.scenarioCaseCount = String.valueOf(scenarioCaseCount);
|
||||
this.loadCaseCount = String.valueOf(loadCaseCount);
|
||||
this.allCount = String.valueOf(testCaseCount+apiCaseCount+scenarioCaseCount+loadCaseCount);
|
||||
|
||||
children = new ArrayList<>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package io.metersphere.reportstatistics.dto.charts;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class Legend {
|
||||
private final String x = "center";
|
||||
private final String y = "bottom";
|
||||
private final String type = "scroll";
|
||||
private final List<Integer> padding = Arrays.asList(0, 40, 0, 0);
|
||||
private Map<String, Boolean> selected;
|
||||
private List<String> data;
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package io.metersphere.reportstatistics.dto.charts;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class PieData {
|
||||
private String name;
|
||||
private long value;
|
||||
private JSONObject itemStyle;
|
||||
|
||||
public void setColor(String color){
|
||||
if(itemStyle == null){
|
||||
itemStyle = new JSONObject();
|
||||
}
|
||||
itemStyle.put("color",color);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package io.metersphere.reportstatistics.dto.charts;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class Series {
|
||||
private String name;
|
||||
private List<Object> data;
|
||||
private String color = "#783887";
|
||||
private String type = "line";
|
||||
private String radius = "50";
|
||||
private String stack;
|
||||
private JSONObject encode;
|
||||
private List<String> center;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package io.metersphere.reportstatistics.dto.charts;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class Title {
|
||||
private String name;
|
||||
private String subtext;
|
||||
private String left;
|
||||
private String top = "75%";
|
||||
private String textAlign = "center";
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package io.metersphere.reportstatistics.dto.charts;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class XAxis {
|
||||
private final String type = "category";
|
||||
private List<String> data;
|
||||
private String name;
|
||||
private Map<String,Integer> axisLabel = new HashMap<String,Integer>(){ {this.put("interval",0);this.put("rotate",30);}};
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package io.metersphere.reportstatistics.dto.charts;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class YAxis {
|
||||
private String type;
|
||||
private List<String> data;
|
||||
private String name;
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package io.metersphere.reportstatistics.service;
|
||||
|
||||
import io.metersphere.base.domain.ReportStatistics;
|
||||
import io.metersphere.base.domain.ReportStatisticsExample;
|
||||
import io.metersphere.base.domain.ReportStatisticsWithBLOBs;
|
||||
import io.metersphere.base.mapper.ReportStatisticsMapper;
|
||||
import io.metersphere.commons.utils.SessionUtils;
|
||||
import io.metersphere.reportstatistics.dto.ReportStatisticsSaveRequest;
|
||||
import io.metersphere.reportstatistics.dto.ReportStatisticsType;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author song.tianyang
|
||||
* @Date 2021/9/14 4:50 下午
|
||||
*/
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class ReportStatisticsService {
|
||||
@Resource
|
||||
private ReportStatisticsMapper reportStatisticsMapper;
|
||||
|
||||
public ReportStatisticsWithBLOBs saveByRequest(ReportStatisticsSaveRequest request) {
|
||||
ReportStatisticsWithBLOBs model = new ReportStatisticsWithBLOBs();
|
||||
model.setId(UUID.randomUUID().toString());
|
||||
String name = "用例分析报表";
|
||||
if(StringUtils.equalsIgnoreCase(ReportStatisticsType.TEST_CASE_COUNT.name(),request.getReportType())){
|
||||
name = "用例统计报表";
|
||||
model.setReportType(ReportStatisticsType.TEST_CASE_COUNT.name());
|
||||
}else {
|
||||
model.setReportType(ReportStatisticsType.TEST_CASE_ANALYSIS.name());
|
||||
}
|
||||
model.setName(name);
|
||||
model.setDataOption(request.getDataOption());
|
||||
model.setSelectOption(request.getSelectOption());
|
||||
model.setCreateTime(System.currentTimeMillis());
|
||||
model.setUpdateTime(System.currentTimeMillis());
|
||||
model.setProjectId(request.getProjectId());
|
||||
String userId = SessionUtils.getUserId();
|
||||
model.setCreateUser(userId);
|
||||
model.setUpdateUser(userId);
|
||||
|
||||
reportStatisticsMapper.insert(model);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
public int deleteById(String id) {
|
||||
return reportStatisticsMapper.deleteByPrimaryKey(id);
|
||||
}
|
||||
|
||||
public List<ReportStatistics> selectByProjectIdAndReportType(String projectId, String reportType) {
|
||||
ReportStatisticsExample example = new ReportStatisticsExample();
|
||||
example.createCriteria().andProjectIdEqualTo(projectId).andReportTypeEqualTo(reportType);
|
||||
example.setOrderByClause("create_time DESC");
|
||||
return reportStatisticsMapper.selectByExample(example);
|
||||
}
|
||||
|
||||
public ReportStatisticsWithBLOBs selectById(String id) {
|
||||
return reportStatisticsMapper.selectByPrimaryKey(id);
|
||||
}
|
||||
|
||||
public ReportStatisticsWithBLOBs updateByRequest(ReportStatisticsSaveRequest request) {
|
||||
ReportStatisticsWithBLOBs updateModel = new ReportStatisticsWithBLOBs();
|
||||
updateModel.setId(request.getId());
|
||||
updateModel.setName(request.getName());
|
||||
updateModel.setUpdateTime(request.getUpdateTime());
|
||||
updateModel.setUpdateUser(SessionUtils.getUserId());
|
||||
reportStatisticsMapper.updateByPrimaryKeySelective(updateModel);
|
||||
return updateModel;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
package io.metersphere.reportstatistics.service;
|
||||
|
||||
import io.metersphere.base.mapper.ext.ExtTestAnalysisMapper;
|
||||
import io.metersphere.commons.utils.DateUtils;
|
||||
import io.metersphere.commons.utils.SessionUtils;
|
||||
import io.metersphere.controller.request.ProjectRequest;
|
||||
import io.metersphere.dto.ProjectDTO;
|
||||
import io.metersphere.reportstatistics.dto.*;
|
||||
import io.metersphere.reportstatistics.dto.charts.Legend;
|
||||
import io.metersphere.reportstatistics.dto.charts.Series;
|
||||
import io.metersphere.reportstatistics.dto.charts.XAxis;
|
||||
import io.metersphere.reportstatistics.dto.charts.YAxis;
|
||||
import io.metersphere.service.ProjectService;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class TestAnalysisService {
|
||||
@Resource
|
||||
private ExtTestAnalysisMapper extTestAnalysisMapper;
|
||||
@Resource
|
||||
private ProjectService projectService;
|
||||
|
||||
private final String ADD = "新增用例";
|
||||
private final String UPDATE = "修改用例";
|
||||
|
||||
public TestAnalysisResult getReport(TestAnalysisChartRequest request) {
|
||||
if (CollectionUtils.isEmpty(request.getTimes())) {
|
||||
// 最近七天
|
||||
request.setTimes(Arrays.asList(System.currentTimeMillis() - 7 * 24 * 3600 * 1000L, System.currentTimeMillis()));
|
||||
}
|
||||
request.setStartTime(DateUtils.getDataStr(request.getTimes().get(0)));
|
||||
request.setEndTime(DateUtils.getDataStr(request.getTimes().get(1)));
|
||||
if (CollectionUtils.isEmpty(request.getProjects())) {
|
||||
// 获取当前组织空间下所有项目
|
||||
String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId();
|
||||
ProjectRequest projectRequest = new ProjectRequest();
|
||||
projectRequest.setWorkspaceId(currentWorkspaceId);
|
||||
List<ProjectDTO> projectDTOS = projectService.getProjectList(projectRequest);
|
||||
if (CollectionUtils.isNotEmpty(projectDTOS)) {
|
||||
request.setProjects(projectDTOS.stream().map(ProjectDTO::getId).collect(Collectors.toList()));
|
||||
} else {
|
||||
request.setProjects(new LinkedList<String>(){{this.add(UUID.randomUUID().toString());}});
|
||||
}
|
||||
}
|
||||
TestAnalysisChartDTO dto = new TestAnalysisChartDTO();
|
||||
List<TestAnalysisTableDTO> dtos = new LinkedList<>();
|
||||
|
||||
List<Series> seriesList = new LinkedList<>();
|
||||
XAxis xAxis = new XAxis();
|
||||
|
||||
if (CollectionUtils.isEmpty(request.getUsers())) {
|
||||
// 组织charts格式数据
|
||||
Legend legend = new Legend();
|
||||
formatLegend(legend, null, request);
|
||||
dto.setLegend(legend);
|
||||
List<TestAnalysisChartResult> createResults = extTestAnalysisMapper.getCraeteCaseReport(request);
|
||||
// 获取修改的用例统计报表
|
||||
List<TestAnalysisChartResult> updateResults = extTestAnalysisMapper.getUpdateCaseReport(request);
|
||||
formatXaxisSeries(xAxis, seriesList, "", dto, createResults, updateResults);
|
||||
formatTable(dtos, createResults, updateResults);
|
||||
} else {
|
||||
List<String> users = request.getUsers();
|
||||
Legend legend = new Legend();
|
||||
formatLegend(legend, users, request);
|
||||
dto.setLegend(legend);
|
||||
|
||||
// 按用户展示
|
||||
boolean isFlag = true;
|
||||
for (String item : users) {
|
||||
request.setUsers(Arrays.asList(item));
|
||||
List<TestAnalysisChartResult> createResults = extTestAnalysisMapper.getCraeteCaseReport(request);
|
||||
// 获取修改的用例统计报表
|
||||
List<TestAnalysisChartResult> updateResults = extTestAnalysisMapper.getUpdateCaseReport(request);
|
||||
formatXaxisSeries(xAxis, seriesList, item + "-", dto, createResults, updateResults);
|
||||
|
||||
// 初始化列表总量,按天统计总量
|
||||
if (isFlag) {
|
||||
formatTable(dtos, createResults, updateResults);
|
||||
isFlag = false;
|
||||
}
|
||||
// 增加子项
|
||||
for (int j = 0; j < dtos.size(); j++) {
|
||||
TestAnalysisTableDTO childItem = new TestAnalysisTableDTO(item, createResults.get(j).getCountNum(), updateResults.get(j).getCountNum(), null);
|
||||
dtos.get(j).getChildren().add(childItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 每行总计
|
||||
dtos.forEach(item -> {
|
||||
if (CollectionUtils.isNotEmpty(item.getChildren())) {
|
||||
// table 总和计算
|
||||
List<Integer> collect = item.getChildren().stream().map(childItem -> Integer.valueOf(childItem.getCreateCount())).collect(Collectors.toList());
|
||||
// reduce求和
|
||||
Optional<Integer> createCount = collect.stream().reduce(Integer::sum);
|
||||
List<Integer> upCollect = item.getChildren().stream().map(childItem -> Integer.valueOf(childItem.getUpdateCount())).collect(Collectors.toList());
|
||||
// reduce求和
|
||||
Optional<Integer> updateCount = upCollect.stream().reduce(Integer::sum);
|
||||
item.setCreateCount(createCount.get().toString());
|
||||
item.setUpdateCount(updateCount.get().toString());
|
||||
}
|
||||
});
|
||||
// table 总和计算
|
||||
List<Integer> collect = dtos.stream().map(item -> Integer.valueOf(item.getCreateCount())).collect(Collectors.toList());
|
||||
// reduce求和
|
||||
Optional<Integer> createCount = collect.stream().reduce(Integer::sum);
|
||||
List<Integer> upCollect = dtos.stream().map(item -> Integer.valueOf(item.getUpdateCount())).collect(Collectors.toList());
|
||||
// reduce求和
|
||||
Optional<Integer> updateCount = upCollect.stream().reduce(Integer::sum);
|
||||
dtos.add(new TestAnalysisTableDTO("总计", createCount.get().toString(), updateCount.get().toString(), new LinkedList<>()));
|
||||
|
||||
TestAnalysisResult testAnalysisResult = new TestAnalysisResult();
|
||||
testAnalysisResult.setChartDTO(dto);
|
||||
testAnalysisResult.setTableDTOs(dtos);
|
||||
return testAnalysisResult;
|
||||
}
|
||||
|
||||
private void formatXaxisSeries(XAxis xAxis, List<Series> seriesList, String name, TestAnalysisChartDTO dto, List<TestAnalysisChartResult> createResults, List<TestAnalysisChartResult> updateResults) {
|
||||
if (CollectionUtils.isNotEmpty(createResults)) {
|
||||
xAxis.setData(createResults.stream().map(TestAnalysisChartResult::getDateStr).collect(Collectors.toList()));
|
||||
Series series = new Series();
|
||||
series.setName(name + ADD);
|
||||
series.setData(createResults.stream().map(TestAnalysisChartResult::getCountNum).collect(Collectors.toList()));
|
||||
seriesList.add(series);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(updateResults)) {
|
||||
xAxis.setData(updateResults.stream().map(TestAnalysisChartResult::getDateStr).collect(Collectors.toList()));
|
||||
Series series = new Series();
|
||||
series.setName(name + UPDATE);
|
||||
series.setColor("#B8741A");
|
||||
series.setData(updateResults.stream().map(TestAnalysisChartResult::getCountNum).collect(Collectors.toList()));
|
||||
seriesList.add(series);
|
||||
}
|
||||
dto.setXAxis(xAxis);
|
||||
dto.setYAxis(new YAxis());
|
||||
dto.setSeries(seriesList);
|
||||
}
|
||||
|
||||
private void formatLegend(Legend legend, List<String> datas, TestAnalysisChartRequest request) {
|
||||
Map<String, Boolean> selected = new LinkedHashMap<>();
|
||||
List<String> list = new LinkedList<>();
|
||||
if (CollectionUtils.isEmpty(datas)) {
|
||||
selected.put(ADD, request.isCreateCase());
|
||||
selected.put(UPDATE, request.isUpdateCase());
|
||||
list.add(ADD);
|
||||
list.add(UPDATE);
|
||||
} else {
|
||||
datas.forEach(item -> {
|
||||
selected.put(item + "-" + ADD, request.isCreateCase());
|
||||
selected.put(item + "-" + UPDATE, request.isUpdateCase());
|
||||
list.add(item + "-" + ADD);
|
||||
list.add(item + "-" + UPDATE);
|
||||
});
|
||||
}
|
||||
legend.setSelected(selected);
|
||||
legend.setData(list);
|
||||
}
|
||||
|
||||
private void formatTable(List<TestAnalysisTableDTO> dtos, List<TestAnalysisChartResult> createResults, List<TestAnalysisChartResult> updateResults) {
|
||||
for (int i = 0; i < createResults.size(); i++) {
|
||||
TestAnalysisTableDTO dto = new TestAnalysisTableDTO(createResults.get(i).getDateStr(), createResults.get(i).getCountNum(), updateResults.get(i).getCountNum(), new LinkedList<>());
|
||||
dtos.add(dto);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,775 @@
|
|||
package io.metersphere.reportstatistics.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.metersphere.base.domain.CustomField;
|
||||
import io.metersphere.base.domain.User;
|
||||
import io.metersphere.base.mapper.ext.ExtTestCaseCountMapper;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.commons.utils.DateUtils;
|
||||
import io.metersphere.controller.request.member.QueryMemberRequest;
|
||||
import io.metersphere.dto.TestCaseTemplateDao;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.reportstatistics.dto.*;
|
||||
import io.metersphere.reportstatistics.dto.charts.*;
|
||||
import io.metersphere.service.TestCaseTemplateService;
|
||||
import io.metersphere.service.UserService;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class TestCaseCountService {
|
||||
@Resource
|
||||
private ExtTestCaseCountMapper extTestCaseCountMapper;
|
||||
@Resource
|
||||
UserService userService;
|
||||
|
||||
public TestCaseCountResponse getReport(TestCaseCountRequest request) {
|
||||
request.setFilterType(request.getFilterType().toUpperCase(Locale.ROOT));
|
||||
|
||||
TestAnalysisChartDTO dto = new TestAnalysisChartDTO();
|
||||
PieChartDTO pieChartDTO = new PieChartDTO();
|
||||
List<TestCaseCountTableDTO> dtos = new LinkedList<>();
|
||||
|
||||
List<Series> seriesList = new LinkedList<>();
|
||||
XAxis xAxis = new XAxis();
|
||||
xAxis.setAxisLabel(new HashMap<String,Integer>(){ {this.put("interval",0);this.put("rotate",0);}});
|
||||
|
||||
// 组织charts格式数据
|
||||
Legend legend = new Legend();
|
||||
formatLegend(legend, request.getYaxis(), request);
|
||||
dto.setLegend(legend);
|
||||
//根据X轴(分组计算字段)来整理不同表对应的字段 注意:x轴维护人/查询条件有维护人时 不查接口和性能; x轴为用例等级/查询条件有用例等级的,不查性能
|
||||
|
||||
boolean yAxisSelectTestCase = false;
|
||||
boolean yAxisSelectApi = false;
|
||||
boolean yAxisSelectScenarioCase = false;
|
||||
boolean yAxisSelectLoad = false;
|
||||
|
||||
boolean selectApi = true;
|
||||
boolean selectLoad = true;
|
||||
|
||||
boolean parseUser = false;
|
||||
boolean parseStatus = false;
|
||||
|
||||
switch (request.getXaxis()) {
|
||||
case "creator":
|
||||
request.setTestCaseGroupColumn("create_user");
|
||||
request.setApiCaseGroupColumn("create_user_id");
|
||||
request.setScenarioCaseGroupColumn("create_user");
|
||||
request.setLoadCaseGroupColumn("create_user");
|
||||
parseUser = true;
|
||||
break;
|
||||
case "maintainer":
|
||||
request.setTestCaseGroupColumn("maintainer");
|
||||
request.setApiCaseGroupColumn("'无维护人'");
|
||||
request.setScenarioCaseGroupColumn("principal");
|
||||
request.setLoadCaseGroupColumn("'无维护人'");
|
||||
selectApi = false;
|
||||
selectLoad = false;
|
||||
parseUser = true;
|
||||
break;
|
||||
case "casetype":
|
||||
Map<String, String> caseDescMap = this.getCaseDescMap();
|
||||
request.setTestCaseGroupColumn("'" + caseDescMap.get("testCaseDesc") + "'");
|
||||
request.setApiCaseGroupColumn("'" + caseDescMap.get("apiCaseDesc") + "'");
|
||||
request.setScenarioCaseGroupColumn("'" + caseDescMap.get("scenarioCaseDesc") + "'");
|
||||
request.setLoadCaseGroupColumn("'" + caseDescMap.get("loadCaseDesc") + "'");
|
||||
break;
|
||||
case "casestatus":
|
||||
request.setTestCaseGroupColumn("status");
|
||||
request.setApiCaseGroupColumn("status");
|
||||
request.setScenarioCaseGroupColumn("status");
|
||||
request.setLoadCaseGroupColumn("status");
|
||||
selectApi = false;
|
||||
parseStatus = true;
|
||||
break;
|
||||
case "caselevel":
|
||||
request.setTestCaseGroupColumn("priority");
|
||||
request.setApiCaseGroupColumn("priority");
|
||||
request.setScenarioCaseGroupColumn("level");
|
||||
request.setLoadCaseGroupColumn("'无用例等级'");
|
||||
selectLoad = false;
|
||||
break;
|
||||
default:
|
||||
return new TestCaseCountResponse();
|
||||
}
|
||||
|
||||
//计算时间
|
||||
if (StringUtils.equalsIgnoreCase(request.getTimeType(), "dynamicTime")) {
|
||||
int dateCountType = 0;
|
||||
if (StringUtils.equalsIgnoreCase(request.getTimeRangeUnit(), "day")) {
|
||||
dateCountType = Calendar.DAY_OF_MONTH;
|
||||
} else if (StringUtils.equalsIgnoreCase(request.getTimeRangeUnit(), "month")) {
|
||||
dateCountType = Calendar.MONTH;
|
||||
} else if (StringUtils.equalsIgnoreCase(request.getTimeRangeUnit(), "year")) {
|
||||
dateCountType = Calendar.YEAR;
|
||||
}
|
||||
|
||||
if (dateCountType != 0 && request.getTimeRange() != 0) {
|
||||
long startTime = DateUtils.dateSum(new Date(), (0 - request.getTimeRange()), dateCountType).getTime();
|
||||
request.setStartTime(startTime);
|
||||
}
|
||||
|
||||
} else if (StringUtils.equalsIgnoreCase(request.getTimeType(), "fixedTime")) {
|
||||
if (CollectionUtils.isNotEmpty(request.getTimes()) && request.getTimes().size() == 2) {
|
||||
request.setStartTime(request.getTimes().get(0));
|
||||
request.setEndTime(request.getTimes().get(1));
|
||||
}
|
||||
}
|
||||
|
||||
//计算更多属性
|
||||
if (CollectionUtils.isNotEmpty(request.getFilters())) {
|
||||
for (Map<String, Object> filterMap : request.getFilters()) {
|
||||
String filterType = String.valueOf(filterMap.get("type"));
|
||||
|
||||
if (StringUtils.equalsAnyIgnoreCase(filterType, "casetype", "caselevel", "creator", "maintainer")) {
|
||||
Object valueObj = filterMap.get("values");
|
||||
if (valueObj instanceof List) {
|
||||
List<String> searchList = (List) valueObj;
|
||||
if(!searchList.isEmpty()){
|
||||
request.setFilterSearchList(filterType, searchList);
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.equalsIgnoreCase(filterType, "caselevel")) {
|
||||
selectLoad = false;
|
||||
}else if (StringUtils.equalsIgnoreCase(filterType, "maintainer")) {
|
||||
selectApi = false;
|
||||
selectLoad = false;
|
||||
}
|
||||
}else if(StringUtils.equalsAnyIgnoreCase(filterType, "casestatus")){
|
||||
List<String> searchList = new ArrayList<>();
|
||||
Object valueObj = filterMap.get("values");
|
||||
if (valueObj instanceof List) {
|
||||
for (String statusStr : (List<String>) valueObj) {
|
||||
searchList.add(statusStr.toUpperCase(Locale.ROOT));
|
||||
}
|
||||
}
|
||||
//如果包含Running
|
||||
if(searchList.contains("RUNNING")){
|
||||
if(!searchList.contains("Starting")){
|
||||
searchList.add("STARTING");
|
||||
}
|
||||
if(!searchList.contains("Underway")){
|
||||
searchList.add("UNDERWAY");
|
||||
}
|
||||
}
|
||||
|
||||
if(searchList.contains("FINISHED")){
|
||||
if(!searchList.contains("Completed")){
|
||||
searchList.add("Completed");
|
||||
}
|
||||
}
|
||||
|
||||
if(!searchList.isEmpty()){
|
||||
request.setFilterSearchList(filterType, searchList);
|
||||
}
|
||||
selectApi = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//获取测试用例、接口用例、场景用例、性能用例的统计
|
||||
List<TestCaseCountChartResult> functionCaseCountResult = new ArrayList<>();
|
||||
List<TestCaseCountChartResult> apiCaseCountResult = new ArrayList<>();
|
||||
List<TestCaseCountChartResult> scenarioCaseCount = new ArrayList<>();
|
||||
List<TestCaseCountChartResult> loadCaseCount = new ArrayList<>();
|
||||
|
||||
List<String> moreOptionsAboutCaseType = new ArrayList<>();
|
||||
if (StringUtils.equalsIgnoreCase(request.getFilterType(), "And") && MapUtils.isNotEmpty(request.getFilterSearchList())) {
|
||||
if (request.getFilterSearchList().containsKey("maintainer")) {
|
||||
selectApi = false;
|
||||
}
|
||||
if (request.getFilterSearchList().containsKey("caselevel")) {
|
||||
selectLoad = false;
|
||||
}
|
||||
|
||||
if (request.getFilterSearchList().containsKey("casetype")) {
|
||||
//如果"且"查询,同时针对案例类型做过筛选,那么则分开批量查询
|
||||
List<String> selectCaseTypeList = request.getFilterSearchList().get("casetype");
|
||||
request.getFilterSearchList().remove("casetype");
|
||||
if (CollectionUtils.isNotEmpty(selectCaseTypeList)) {
|
||||
moreOptionsAboutCaseType.addAll(selectCaseTypeList);
|
||||
}
|
||||
}
|
||||
}
|
||||
//没有选择的话默认搜索条件是所有类型的案例
|
||||
if(moreOptionsAboutCaseType.isEmpty()){
|
||||
moreOptionsAboutCaseType.add("testCase");
|
||||
moreOptionsAboutCaseType.add("apiCase");
|
||||
moreOptionsAboutCaseType.add("scenarioCase");
|
||||
moreOptionsAboutCaseType.add("loadCase");
|
||||
}
|
||||
|
||||
//解析Y轴,判断要查询的案例类型
|
||||
if(CollectionUtils.isNotEmpty(request.getYaxis())){
|
||||
|
||||
for (String selectType:request.getYaxis()) {
|
||||
if(moreOptionsAboutCaseType.contains(selectType)){
|
||||
if (StringUtils.equalsIgnoreCase(selectType, "testCase")) {
|
||||
yAxisSelectTestCase = true;
|
||||
} else if (StringUtils.equalsIgnoreCase(selectType, "apiCase")) {
|
||||
if(selectApi){
|
||||
yAxisSelectApi = true;
|
||||
}
|
||||
} else if (StringUtils.equalsIgnoreCase(selectType, "scenarioCase")) {
|
||||
yAxisSelectScenarioCase = true;
|
||||
} else if (StringUtils.equalsIgnoreCase(selectType, "loadCase")) {
|
||||
if(selectLoad){
|
||||
yAxisSelectLoad = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(yAxisSelectTestCase){
|
||||
functionCaseCountResult = extTestCaseCountMapper.getFunctionCaseCount(request);
|
||||
}
|
||||
if (yAxisSelectApi) {
|
||||
Map<String,List<String>> apiCaseFilterList = new HashMap<>();
|
||||
if(MapUtils.isNotEmpty(request.getFilterSearchList())){
|
||||
for (Map.Entry<String,List<String>> entry : request.getFilterSearchList().entrySet()) {
|
||||
String type = entry.getKey();
|
||||
if(!StringUtils.equalsAnyIgnoreCase(type,"maintainer","casestatus")){
|
||||
apiCaseFilterList.put(entry.getKey(),entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
request.setApiFilterSearchList(apiCaseFilterList);
|
||||
apiCaseCountResult = extTestCaseCountMapper.getApiCaseCount(request);
|
||||
}
|
||||
if(yAxisSelectScenarioCase){
|
||||
scenarioCaseCount = extTestCaseCountMapper.getScenarioCaseCount(request);
|
||||
}
|
||||
if (yAxisSelectLoad) {
|
||||
Map<String,List<String>> loadCaseFilterMap = new HashMap<>();
|
||||
if(MapUtils.isNotEmpty(request.getFilterSearchList())){
|
||||
for (Map.Entry<String,List<String>> entry : request.getFilterSearchList().entrySet()) {
|
||||
String type = entry.getKey();
|
||||
if(!StringUtils.equalsAnyIgnoreCase(type,"maintainer","caselevel")){
|
||||
loadCaseFilterMap.put(entry.getKey(),entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
request.setLoadFilterSearchList(loadCaseFilterMap);
|
||||
loadCaseCount = extTestCaseCountMapper.getLoadCaseCount(request);
|
||||
}
|
||||
|
||||
Map<String, TestCaseCountSummary> summaryMap = this.summaryCountResult(parseUser, parseStatus,request.getProjectId(),request.getOrder(),
|
||||
functionCaseCountResult, apiCaseCountResult, scenarioCaseCount, loadCaseCount);
|
||||
|
||||
formatXaxisSeries(xAxis, seriesList, dto, summaryMap);
|
||||
formatTable(dtos, summaryMap);
|
||||
|
||||
formatPieChart(pieChartDTO, request.getXaxis(), summaryMap,yAxisSelectTestCase,yAxisSelectApi,yAxisSelectScenarioCase,yAxisSelectLoad);
|
||||
|
||||
TestCaseCountResponse testCaseCountResult = new TestCaseCountResponse();
|
||||
testCaseCountResult.setBarChartDTO(dto);
|
||||
testCaseCountResult.setTableDTOs(dtos);
|
||||
testCaseCountResult.setPieChartDTO(pieChartDTO);
|
||||
return testCaseCountResult;
|
||||
}
|
||||
|
||||
private void formatPieChart(PieChartDTO pieChartDTO, String groupName, Map<String, TestCaseCountSummary> summaryMap,
|
||||
boolean selectTestCase, boolean selectApi, boolean selectScenarioCase, boolean selectLoad) {
|
||||
JSONArray titleArray = new JSONArray();
|
||||
titleArray.add("type");
|
||||
titleArray.add("count");
|
||||
titleArray.add(groupName);
|
||||
|
||||
List<Series> seriesArr = new ArrayList<>();
|
||||
List<Title> titles = new ArrayList<>();
|
||||
|
||||
int leftPx = 200;
|
||||
Map<String, String> caseDescMap = this.getCaseDescMap();
|
||||
for (TestCaseCountSummary summary : summaryMap.values()) {
|
||||
String leftPxStr = String.valueOf(leftPx);
|
||||
|
||||
List<Object> dataList = new ArrayList<>();
|
||||
|
||||
if(selectTestCase && summary.testCaseCount > 0){
|
||||
PieData pieData = new PieData();
|
||||
pieData.setName(caseDescMap.get("testCaseDesc"));
|
||||
pieData.setValue(summary.testCaseCount);
|
||||
pieData.setColor("#F38F1F");
|
||||
dataList.add(pieData);
|
||||
}
|
||||
|
||||
if(selectApi && summary.apiCaseCount > 0){
|
||||
PieData apicasePieData = new PieData();
|
||||
apicasePieData.setName(caseDescMap.get("apiCaseDesc"));
|
||||
apicasePieData.setValue(summary.apiCaseCount);
|
||||
apicasePieData.setColor("#6FD999");
|
||||
dataList.add(apicasePieData);
|
||||
}
|
||||
|
||||
if(selectScenarioCase && summary.scenarioCaseCount > 0){
|
||||
PieData scenarioPieData = new PieData();
|
||||
scenarioPieData.setName(caseDescMap.get("scenarioCaseDesc"));
|
||||
scenarioPieData.setValue(summary.scenarioCaseCount);
|
||||
scenarioPieData.setColor("#2884F3");
|
||||
dataList.add(scenarioPieData);
|
||||
}
|
||||
|
||||
if(selectLoad && summary.loadCaseCount > 0){
|
||||
PieData loadCasePieData = new PieData();
|
||||
loadCasePieData.setName(caseDescMap.get("loadCaseDesc"));
|
||||
loadCasePieData.setValue(summary.loadCaseCount);
|
||||
loadCasePieData.setColor("#F45E53");
|
||||
dataList.add(loadCasePieData);
|
||||
}
|
||||
|
||||
Series series = new Series();
|
||||
series.setType("pie");
|
||||
series.setRadius("50");
|
||||
series.setEncode(new JSONObject() {{
|
||||
this.put("itemName", "groupname");
|
||||
this.put("value", summary.groupName);
|
||||
}});
|
||||
seriesArr.add(series);
|
||||
|
||||
series.setData(dataList);
|
||||
series.setCenter(new ArrayList<String>() {{
|
||||
this.add(leftPxStr);
|
||||
this.add("50%");
|
||||
}});
|
||||
|
||||
Title title = new Title();
|
||||
title.setSubtext(summary.groupName);
|
||||
title.setLeft(leftPxStr);
|
||||
titles.add(title);
|
||||
|
||||
leftPx = leftPx + 350;
|
||||
}
|
||||
|
||||
pieChartDTO.setSeries(seriesArr);
|
||||
pieChartDTO.setTitle(titles);
|
||||
pieChartDTO.setWidth(leftPx);
|
||||
}
|
||||
|
||||
private Map<String, TestCaseCountSummary> summaryCountResult(boolean parseGroupNameToUserName, boolean parseGrouNameToCaseStatus, String projectId, String order,
|
||||
List<TestCaseCountChartResult> functionCaseCountResult, List<TestCaseCountChartResult> apiCaseCountResult, List<TestCaseCountChartResult> scenarioCaseCount, List<TestCaseCountChartResult> loadCaseCount) {
|
||||
Map<String, TestCaseCountSummary> summaryMap = new LinkedHashMap<>();
|
||||
|
||||
//groupName 解析对象
|
||||
Map<String, String> groupNameParseMap = new HashMap<>();
|
||||
if (parseGroupNameToUserName) {
|
||||
groupNameParseMap.putAll(this.getUserIdMap());
|
||||
}
|
||||
if (parseGrouNameToCaseStatus) {
|
||||
groupNameParseMap.putAll(this.getCaseStatusMap(projectId));
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(functionCaseCountResult)) {
|
||||
for (TestCaseCountChartResult result : functionCaseCountResult) {
|
||||
if(result.getGroupName() == null){
|
||||
result.setGroupName(groupNameParseMap.get("running"));
|
||||
}else {
|
||||
if (groupNameParseMap.containsKey(result.getGroupName().toLowerCase(Locale.ROOT))) {
|
||||
result.setGroupName(groupNameParseMap.get(result.getGroupName().toLowerCase(Locale.ROOT)));
|
||||
}
|
||||
}
|
||||
|
||||
String groupName = result.getGroupName();
|
||||
if (StringUtils.isNotEmpty(groupName)) {
|
||||
TestCaseCountSummary summary = summaryMap.get(groupName);
|
||||
if (summary == null) {
|
||||
summary = new TestCaseCountSummary(groupName);
|
||||
}
|
||||
summary.testCaseCount = result.getCountNum();
|
||||
summaryMap.put(groupName, summary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(apiCaseCountResult)) {
|
||||
for (TestCaseCountChartResult result : apiCaseCountResult) {
|
||||
if(result.getGroupName() == null){
|
||||
result.setGroupName(groupNameParseMap.get("running"));
|
||||
}else {
|
||||
if (groupNameParseMap.containsKey(result.getGroupName().toLowerCase(Locale.ROOT))) {
|
||||
result.setGroupName(groupNameParseMap.get(result.getGroupName().toLowerCase(Locale.ROOT)));
|
||||
}
|
||||
}
|
||||
String groupName = result.getGroupName();
|
||||
if (StringUtils.isNotEmpty(groupName)) {
|
||||
TestCaseCountSummary summary = summaryMap.get(groupName);
|
||||
if (summary == null) {
|
||||
summary = new TestCaseCountSummary(groupName);
|
||||
}
|
||||
summary.apiCaseCount = result.getCountNum();
|
||||
summaryMap.put(groupName, summary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(scenarioCaseCount)) {
|
||||
for (TestCaseCountChartResult result : scenarioCaseCount) {
|
||||
if(result.getGroupName() == null){
|
||||
result.setGroupName(groupNameParseMap.get("running"));
|
||||
}else {
|
||||
if (groupNameParseMap.containsKey(result.getGroupName().toLowerCase(Locale.ROOT))) {
|
||||
result.setGroupName(groupNameParseMap.get(result.getGroupName().toLowerCase(Locale.ROOT)));
|
||||
}
|
||||
}
|
||||
String groupName = result.getGroupName();
|
||||
if (StringUtils.isNotEmpty(groupName)) {
|
||||
TestCaseCountSummary summary = summaryMap.get(groupName);
|
||||
if (summary == null) {
|
||||
summary = new TestCaseCountSummary(groupName);
|
||||
}
|
||||
summary.scenarioCaseCount = result.getCountNum();
|
||||
summaryMap.put(groupName, summary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(loadCaseCount)) {
|
||||
for (TestCaseCountChartResult result : loadCaseCount) {
|
||||
if(result.getGroupName() == null){
|
||||
result.setGroupName(groupNameParseMap.get("running"));
|
||||
}else {
|
||||
if (groupNameParseMap.containsKey(result.getGroupName().toLowerCase(Locale.ROOT))) {
|
||||
result.setGroupName(groupNameParseMap.get(result.getGroupName().toLowerCase(Locale.ROOT)));
|
||||
}
|
||||
}
|
||||
String groupName = result.getGroupName();
|
||||
if (StringUtils.isNotEmpty(groupName)) {
|
||||
TestCaseCountSummary summary = summaryMap.get(groupName);
|
||||
if (summary == null) {
|
||||
summary = new TestCaseCountSummary(groupName);
|
||||
}
|
||||
summary.loadCaseCount = result.getCountNum();
|
||||
summaryMap.put(groupName, summary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, TestCaseCountSummary> returmMap = new LinkedHashMap<>();
|
||||
|
||||
if(StringUtils.equalsIgnoreCase(order,"desc")){
|
||||
TreeMap<Long,List<TestCaseCountSummary>> treeMap = new TreeMap<>();
|
||||
for (TestCaseCountSummary model : summaryMap.values()) {
|
||||
if(treeMap.containsKey(model.getAllCount())){
|
||||
treeMap.get(model.getAllCount()).add(model);
|
||||
}else {
|
||||
List<TestCaseCountSummary> list = new ArrayList<>();
|
||||
list.add(model);
|
||||
treeMap.put(model.getAllCount(),list);
|
||||
}
|
||||
}
|
||||
ArrayList<TestCaseCountSummary> sortedList = new ArrayList<>();
|
||||
for (List<TestCaseCountSummary> list : treeMap.values()) {
|
||||
sortedList.addAll(list);
|
||||
}
|
||||
|
||||
for (int i = sortedList.size(); i > 0; i --) {
|
||||
TestCaseCountSummary model = sortedList.get(i-1);
|
||||
returmMap.put(model.groupName,model);
|
||||
}
|
||||
}else if(StringUtils.equalsIgnoreCase(order,"asc")){
|
||||
TreeMap<Long,List<TestCaseCountSummary>> treeMap = new TreeMap<>();
|
||||
for (TestCaseCountSummary model : summaryMap.values()) {
|
||||
if(treeMap.containsKey(model.getAllCount())){
|
||||
treeMap.get(model.getAllCount()).add(model);
|
||||
}else {
|
||||
List<TestCaseCountSummary> list = new ArrayList<>();
|
||||
list.add(model);
|
||||
treeMap.put(model.getAllCount(),list);
|
||||
}
|
||||
}
|
||||
for (List<TestCaseCountSummary> list : treeMap.values()) {
|
||||
for (TestCaseCountSummary model : list ) {
|
||||
returmMap.put(model.groupName,model);
|
||||
}
|
||||
}
|
||||
}else {
|
||||
returmMap = summaryMap;
|
||||
}
|
||||
|
||||
|
||||
return returmMap;
|
||||
}
|
||||
|
||||
private Map<String, String> getUserIdMap() {
|
||||
List<User> userList = userService.getUserList();
|
||||
Map<String, String> userIdMap = new HashMap<>();
|
||||
for (User model : userList) {
|
||||
userIdMap.put(model.getId(), model.getId() + "\n(" + model.getName() + ")");
|
||||
}
|
||||
return userIdMap;
|
||||
}
|
||||
|
||||
private Map<String, String> getCaseStatusMap(String projectId) {
|
||||
|
||||
Map<String, String> caseStatusMap = new HashMap<>();
|
||||
|
||||
TestCaseTemplateService testCaseTemplateService = CommonBeanFactory.getBean(TestCaseTemplateService.class);
|
||||
TestCaseTemplateDao testCaseTemplate = testCaseTemplateService.getTemplate(projectId);
|
||||
|
||||
caseStatusMap.put("prepare", Translator.get("test_case_status_prepare"));
|
||||
caseStatusMap.put("error", Translator.get("test_case_status_error"));
|
||||
caseStatusMap.put("success", Translator.get("test_case_status_success"));
|
||||
caseStatusMap.put("trash", Translator.get("test_case_status_trash"));
|
||||
caseStatusMap.put("underway", Translator.get("test_case_status_running"));
|
||||
caseStatusMap.put("starting", Translator.get("test_case_status_running"));
|
||||
caseStatusMap.put("saved", Translator.get("test_case_status_saved"));
|
||||
caseStatusMap.put("running", Translator.get("test_case_status_running"));
|
||||
caseStatusMap.put("finished", Translator.get("test_case_status_finished"));
|
||||
caseStatusMap.put("completed", Translator.get("test_case_status_finished"));
|
||||
|
||||
if (testCaseTemplate != null && CollectionUtils.isNotEmpty(testCaseTemplate.getCustomFields())) {
|
||||
for (CustomField customField : testCaseTemplate.getCustomFields()) {
|
||||
if (StringUtils.equals(customField.getName(), "用例状态")) {
|
||||
JSONArray optionsArr = JSONArray.parseArray(customField.getOptions());
|
||||
for (int i = 0; i < optionsArr.size(); i++) {
|
||||
JSONObject jsonObject = optionsArr.getJSONObject(i);
|
||||
if (jsonObject.containsKey("value") && jsonObject.containsKey("text") &&
|
||||
!StringUtils.equalsAnyIgnoreCase(jsonObject.getString("value"), "Prepare", "Error", "Success", "Trash", "Underway", "Starting", "Saved")) {
|
||||
caseStatusMap.put(jsonObject.getString("value"), jsonObject.getString("text"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return caseStatusMap;
|
||||
}
|
||||
|
||||
|
||||
private void formatXaxisSeries(XAxis xAxis, List<Series> seriesList, TestAnalysisChartDTO dto,
|
||||
Map<String, TestCaseCountSummary> summaryMap) {
|
||||
List<String> xAxisDataList = new ArrayList<>();
|
||||
|
||||
List<Object> testCaseCountList = new ArrayList<>();
|
||||
List<Object> apiCaseCountList = new ArrayList<>();
|
||||
List<Object> scenarioCaseCountList = new ArrayList<>();
|
||||
List<Object> loadCaseCountList = new ArrayList<>();
|
||||
for (TestCaseCountSummary summary : summaryMap.values()) {
|
||||
xAxisDataList.add(summary.groupName);
|
||||
testCaseCountList.add(String.valueOf(summary.testCaseCount));
|
||||
apiCaseCountList.add(String.valueOf(summary.apiCaseCount));
|
||||
scenarioCaseCountList.add(String.valueOf(summary.scenarioCaseCount));
|
||||
loadCaseCountList.add(String.valueOf(summary.loadCaseCount));
|
||||
}
|
||||
xAxis.setData(xAxisDataList);
|
||||
|
||||
Map<String, String> caseDescMap = this.getCaseDescMap();
|
||||
|
||||
Series tetcaseSeries = new Series();
|
||||
tetcaseSeries.setName(caseDescMap.get("testCaseDesc"));
|
||||
tetcaseSeries.setColor("#F38F1F");
|
||||
tetcaseSeries.setRadius("20%");
|
||||
tetcaseSeries.setType("bar");
|
||||
tetcaseSeries.setStack("total");
|
||||
tetcaseSeries.setData(testCaseCountList);
|
||||
seriesList.add(tetcaseSeries);
|
||||
|
||||
Series apiSeries = new Series();
|
||||
apiSeries.setName(caseDescMap.get("apiCaseDesc"));
|
||||
apiSeries.setColor("#6FD999");
|
||||
apiSeries.setType("bar");
|
||||
apiSeries.setStack("total");
|
||||
apiSeries.setData(apiCaseCountList);
|
||||
seriesList.add(apiSeries);
|
||||
|
||||
Series scenarioSeries = new Series();
|
||||
scenarioSeries.setName(caseDescMap.get("scenarioCaseDesc"));
|
||||
scenarioSeries.setColor("#2884F3");
|
||||
scenarioSeries.setType("bar");
|
||||
scenarioSeries.setStack("total");
|
||||
scenarioSeries.setData(scenarioCaseCountList);
|
||||
seriesList.add(scenarioSeries);
|
||||
|
||||
Series loadSeries = new Series();
|
||||
loadSeries.setName(caseDescMap.get("loadCaseDesc"));
|
||||
loadSeries.setColor("#F45E53");
|
||||
loadSeries.setType("bar");
|
||||
loadSeries.setStack("total");
|
||||
loadSeries.setData(loadCaseCountList);
|
||||
seriesList.add(loadSeries);
|
||||
|
||||
dto.setXAxis(xAxis);
|
||||
dto.setYAxis(new YAxis());
|
||||
dto.setSeries(seriesList);
|
||||
}
|
||||
|
||||
private void formatLegend(Legend legend, List<String> datas, TestCaseCountRequest yrequest) {
|
||||
Map<String, Boolean> selected = new LinkedHashMap<>();
|
||||
List<String> list = new LinkedList<>();
|
||||
legend.setSelected(selected);
|
||||
legend.setData(datas);
|
||||
}
|
||||
|
||||
private void formatTable(List<TestCaseCountTableDTO> dtos, Map<String, TestCaseCountSummary> summaryMap) {
|
||||
for (TestCaseCountSummary summary : summaryMap.values()) {
|
||||
TestCaseCountTableDTO dto = new TestCaseCountTableDTO(summary.groupName, summary.testCaseCount, summary.apiCaseCount, summary.scenarioCaseCount, summary.loadCaseCount);
|
||||
dtos.add(dto);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> getCaseDescMap() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("testCaseDesc", Translator.get("test_case"));
|
||||
map.put("apiCaseDesc", Translator.get("api_case"));
|
||||
map.put("scenarioCaseDesc", Translator.get("scenario_case"));
|
||||
map.put("loadCaseDesc", Translator.get("performance_case"));
|
||||
return map;
|
||||
}
|
||||
|
||||
public Map<String, List<Map<String, String>>> getSelectFilterDatas(String projectId) {
|
||||
Map<String, List<Map<String, String>>> returnMap = new HashMap<>();
|
||||
|
||||
//组装用户
|
||||
QueryMemberRequest memberRequest = new QueryMemberRequest();
|
||||
memberRequest.setProjectId(projectId);
|
||||
List<User> userList = userService.getUserList();
|
||||
|
||||
List<Map<String, String>> returnUserList = new ArrayList<>();
|
||||
for (User user : userList) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("id", user.getId());
|
||||
map.put("label", user.getId() + "(" + user.getName() + ")");
|
||||
returnUserList.add(map);
|
||||
}
|
||||
|
||||
//组装用例等级和用例状态
|
||||
TestCaseTemplateService testCaseTemplateService = CommonBeanFactory.getBean(TestCaseTemplateService.class);
|
||||
TestCaseTemplateDao testCaseTemplate = testCaseTemplateService.getTemplate(projectId);
|
||||
|
||||
List<Map<String, String>> caseLevelList = new ArrayList<>();
|
||||
List<Map<String, String>> caseStatusList = new ArrayList<>();
|
||||
Map<String, String> statusMap1 = new HashMap<>();
|
||||
statusMap1.put("id", "Prepare");
|
||||
statusMap1.put("label", Translator.get("test_case_status_prepare"));
|
||||
|
||||
// Map<String, String> statusMap2 = new HashMap<>();
|
||||
// statusMap2.put("id", "Error");
|
||||
// statusMap2.put("label", Translator.get("test_case_status_error"));
|
||||
//
|
||||
// Map<String, String> statusMap3 = new HashMap<>();
|
||||
// statusMap3.put("id", "Success");
|
||||
// statusMap3.put("label", Translator.get("test_case_status_success"));
|
||||
|
||||
// Map<String, String> statusMap4 = new HashMap<>();
|
||||
// statusMap4.put("id", "Trash");
|
||||
// statusMap4.put("label", Translator.get("test_case_status_trash"));
|
||||
|
||||
// Map<String, String> statusMap5 = new HashMap<>();
|
||||
// statusMap5.put("id", "Underway");
|
||||
// statusMap5.put("label", Translator.get("test_case_status_running"));
|
||||
|
||||
// Map<String, String> statusMap6 = new HashMap<>();
|
||||
// statusMap6.put("id", "Starting");
|
||||
// statusMap6.put("label", Translator.get("test_case_status_running"));
|
||||
|
||||
Map<String, String> statusMap7 = new HashMap<>();
|
||||
statusMap7.put("id", "Saved");
|
||||
statusMap7.put("label", Translator.get("test_case_status_saved"));
|
||||
|
||||
Map<String, String> statusMap8 = new HashMap<>();
|
||||
statusMap8.put("id", "Running");
|
||||
statusMap8.put("label", Translator.get("test_case_status_running"));
|
||||
|
||||
Map<String, String> statusMap9 = new HashMap<>();
|
||||
statusMap9.put("id", "Finished");
|
||||
statusMap9.put("label", Translator.get("test_case_status_finished"));
|
||||
|
||||
caseStatusList.add(statusMap1);
|
||||
// caseStatusList.add(statusMap2);
|
||||
// caseStatusList.add(statusMap3);
|
||||
// caseStatusList.add(statusMap4);
|
||||
// caseStatusList.add(statusMap5);
|
||||
// caseStatusList.add(statusMap6);
|
||||
caseStatusList.add(statusMap7);
|
||||
caseStatusList.add(statusMap8);
|
||||
caseStatusList.add(statusMap9);
|
||||
|
||||
Map<String, String> levelMap1 = new HashMap<>();
|
||||
levelMap1.put("id", "P0");
|
||||
levelMap1.put("label", "P0");
|
||||
Map<String, String> levelMap2 = new HashMap<>();
|
||||
levelMap2.put("id", "P1");
|
||||
levelMap2.put("label", "P1");
|
||||
Map<String, String> levelMap3 = new HashMap<>();
|
||||
levelMap3.put("id", "P2");
|
||||
levelMap3.put("label", "P2");
|
||||
Map<String, String> levelMap4 = new HashMap<>();
|
||||
levelMap4.put("id", "P3");
|
||||
levelMap4.put("label", "P3");
|
||||
caseLevelList.add(levelMap1);
|
||||
caseLevelList.add(levelMap2);
|
||||
caseLevelList.add(levelMap3);
|
||||
caseLevelList.add(levelMap4);
|
||||
|
||||
|
||||
if (testCaseTemplate != null && CollectionUtils.isNotEmpty(testCaseTemplate.getCustomFields())) {
|
||||
for (CustomField customField : testCaseTemplate.getCustomFields()) {
|
||||
if (StringUtils.equals(customField.getName(), "用例状态")) {
|
||||
JSONArray optionsArr = JSONArray.parseArray(customField.getOptions());
|
||||
for (int i = 0; i < optionsArr.size(); i++) {
|
||||
JSONObject jsonObject = optionsArr.getJSONObject(i);
|
||||
if (jsonObject.containsKey("value") && jsonObject.containsKey("text")) {
|
||||
String value = jsonObject.getString("value");
|
||||
if(!StringUtils.equalsAnyIgnoreCase(value, "Prepare", "Error", "Success", "Trash", "Underway", "Starting", "Saved",
|
||||
"Completed","test_track.case.status_finished")){
|
||||
Map<String, String> statusMap = new HashMap<>();
|
||||
statusMap.put("id", jsonObject.getString("value"));
|
||||
statusMap.put("label", jsonObject.getString("text"));
|
||||
caseStatusList.add(statusMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (StringUtils.equals(customField.getName(), "用例等级")) {
|
||||
JSONArray optionsArr = JSONArray.parseArray(customField.getOptions());
|
||||
for (int i = 0; i < optionsArr.size(); i++) {
|
||||
JSONObject jsonObject = optionsArr.getJSONObject(i);
|
||||
if (jsonObject.containsKey("value") && jsonObject.containsKey("text") &&
|
||||
!StringUtils.equalsAnyIgnoreCase(jsonObject.getString("value"), "P0", "P1", "P2", "P3")) {
|
||||
Map<String, String> levelMap = new HashMap<>();
|
||||
levelMap.put("id", jsonObject.getString("value"));
|
||||
levelMap.put("label", jsonObject.getString("text"));
|
||||
caseLevelList.add(levelMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<String, String> caseDescMap = this.getCaseDescMap();
|
||||
// 组装用例类型
|
||||
List<Map<String, String>> caseTypeList = new ArrayList<>();
|
||||
Map<String, String> caseTypeMap1 = new HashMap<>();
|
||||
caseTypeMap1.put("id", "testCase");
|
||||
caseTypeMap1.put("label", caseDescMap.get("testCaseDesc"));
|
||||
Map<String, String> caseTypeMap2 = new HashMap<>();
|
||||
caseTypeMap2.put("id", "apiCase");
|
||||
caseTypeMap2.put("label", caseDescMap.get("apiCaseDesc"));
|
||||
Map<String, String> caseTypeMap3 = new HashMap<>();
|
||||
caseTypeMap3.put("id", "scenarioCase");
|
||||
caseTypeMap3.put("label", caseDescMap.get("scenarioCaseDesc"));
|
||||
Map<String, String> caseTypeMap4 = new HashMap<>();
|
||||
caseTypeMap4.put("id", "loadCase");
|
||||
caseTypeMap4.put("label", caseDescMap.get("loadCaseDesc"));
|
||||
caseTypeList.add(caseTypeMap1);
|
||||
caseTypeList.add(caseTypeMap2);
|
||||
caseTypeList.add(caseTypeMap3);
|
||||
caseTypeList.add(caseTypeMap4);
|
||||
|
||||
returnMap.put("casetype", caseTypeList);
|
||||
returnMap.put("caselevel", caseLevelList);
|
||||
returnMap.put("casestatus", caseStatusList);
|
||||
returnMap.put("creator", returnUserList);
|
||||
returnMap.put("maintainer", returnUserList);
|
||||
return returnMap;
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
Subproject commit bc8f05fdd7bfa0a13438d409394a2d150187f88b
|
||||
Subproject commit 6edae7aeeb9d5ade65d64a115d00af96e4dc56d6
|
|
@ -816,6 +816,18 @@
|
|||
"name": "导出",
|
||||
"resourceId": "PROJECT_REPORT_ANALYSIS",
|
||||
"license": true
|
||||
},
|
||||
{
|
||||
"id": "PROJECT_REPORT_ANALYSIS:READ+UPDATE",
|
||||
"name": "保存",
|
||||
"resourceId": "PROJECT_REPORT_ANALYSIS",
|
||||
"license": true
|
||||
},
|
||||
{
|
||||
"id": "PROJECT_REPORT_ANALYSIS:READ+CREATE",
|
||||
"name": "另存为",
|
||||
"resourceId": "PROJECT_REPORT_ANALYSIS",
|
||||
"license": true
|
||||
}
|
||||
],
|
||||
"resource": [
|
||||
|
|
|
@ -5,11 +5,12 @@ import Setting from "@/business/components/settings/router";
|
|||
import API from "@/business/components/api/router";
|
||||
import Performance from "@/business/components/performance/router";
|
||||
import Track from "@/business/components/track/router";
|
||||
import ReportStatistics from "@/business/components/reportstatistics/router";
|
||||
import {getCurrentUserId} from "@/common/js/utils";
|
||||
|
||||
const requireContext = require.context('@/business/components/xpack/', true, /router\.js$/);
|
||||
const Report = requireContext.keys().map(key => requireContext(key).report);
|
||||
const ReportObj = Report && Report != null && Report.length > 0 && Report[0] != undefined ? Report : [{path: "/sidebar"}];
|
||||
// const requireContext = require.context('@/business/components/xpack/', true, /router\.js$/);
|
||||
// const Report = requireContext.keys().map(key => requireContext(key).report);
|
||||
// const ReportObj = Report && Report != null && Report.length > 0 && Report[0] != undefined ? Report : [{path: "/sidebar"}];
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
|
@ -26,7 +27,8 @@ const router = new VueRouter({
|
|||
API,
|
||||
Performance,
|
||||
Track,
|
||||
...ReportObj
|
||||
ReportStatistics,
|
||||
// ...ReportStatistics
|
||||
]
|
||||
});
|
||||
|
||||
|
|
|
@ -290,11 +290,14 @@ export default {
|
|||
this.$refs.tree.setCheckedKeys(thisKeys);
|
||||
this.returnDataKeys = thisKeys;
|
||||
let t = [];
|
||||
this.options = [];
|
||||
thisKeys.map((item) => {//设置option选项
|
||||
let node = this.$refs.tree.getNode(item); // 所有被选中的节点对应的node
|
||||
t.push(node.data);
|
||||
this.options.push({label: node.label, value: node.key});
|
||||
return {label: node.label, value: node.key};
|
||||
if(node){
|
||||
t.push(node.data);
|
||||
this.options.push({label: node.label, value: node.key});
|
||||
return {label: node.label, value: node.key};
|
||||
}
|
||||
});
|
||||
this.returnDatas = t;
|
||||
this.popoverHide()
|
||||
|
@ -398,6 +401,23 @@ export default {
|
|||
},
|
||||
deep: true
|
||||
},
|
||||
defaultKey:{
|
||||
handler:function(){
|
||||
this.init();
|
||||
if(this.data && this.data.length > 0){
|
||||
this.$refs.tree.setCheckedKeys(this.defaultKey);
|
||||
}
|
||||
},
|
||||
deep:true
|
||||
},
|
||||
data:{
|
||||
handler:function(){
|
||||
if(this.defaultKey && this.defaultKey.length > 0){
|
||||
this.$refs.tree.setCheckedKeys(this.defaultKey);
|
||||
}
|
||||
},
|
||||
deep:true
|
||||
},
|
||||
filterText(val) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.tree.filter(val);
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-row type="flex">
|
||||
<p class="tip">
|
||||
<span class="ms-span">{{$t('commons.report_statistics.name')}}</span>
|
||||
<el-select v-model="reportType" class="ms-col-type" size="mini" style="width: 120px">
|
||||
<el-option :key="t.id" :value="t.id" :label="t.name" v-for="t in reportTypes"/>
|
||||
</el-select>
|
||||
</p>
|
||||
</el-row>
|
||||
<transition>
|
||||
<keep-alive>
|
||||
<report-card @openCard="openCard"/>
|
||||
</keep-alive>
|
||||
</transition>
|
||||
|
||||
<!-- 测试用例趋势页面 -->
|
||||
<ms-drawer :visible="testCaseTrendDrawer" :size="100" @close="close" direction="right" :show-full-screen="false" :is-show-close="false" style="overflow: hidden">
|
||||
<template v-slot:header>
|
||||
<report-header :title="$t('commons.report_statistics.test_case_analysis')" :history-report-id="historyReportId"
|
||||
@closePage="close" @saveReport="saveReport" @selectAndSaveReport="selectAndSaveReport"/>
|
||||
</template>
|
||||
<test-analysis-container @initHistoryReportId="initHistoryReportId" ref="testAnalysisContainer"/>
|
||||
</ms-drawer>
|
||||
|
||||
<!-- 测试用例分析页面 -->
|
||||
<ms-drawer :visible="testCaseCountDrawer" :size="100" @close="close" direction="right" :show-full-screen="false" :is-show-close="false" style="overflow: hidden">
|
||||
<template v-slot:header>
|
||||
<report-header :title="$t('commons.report_statistics.test_case_count')" :history-report-id="historyReportId"
|
||||
@closePage="close" @saveReport="saveReport" @selectAndSaveReport="selectAndSaveReport"/>
|
||||
</template>
|
||||
<test-case-count-container @initHistoryReportId="initHistoryReportId" ref="testCaseCountContainer"/>
|
||||
</ms-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ReportCard from "./ReportCard";
|
||||
import TestAnalysisContainer from "./track/TestAnalysisContainer";
|
||||
import MsDrawer from "@/business/components/common/components/MsDrawer";
|
||||
import ReportHeader from './base/ReportHeader';
|
||||
import TestCaseCountContainer from "./testCaseCount/TestCaseCountContainer";
|
||||
|
||||
export default {
|
||||
name: "ReportAnalysis",
|
||||
components: {ReportCard, TestAnalysisContainer, MsDrawer, ReportHeader, TestCaseCountContainer},
|
||||
data() {
|
||||
return {
|
||||
reportType: "track",
|
||||
testCaseTrendDrawer: false,
|
||||
testCaseCountDrawer: false,
|
||||
historyReportId:"",
|
||||
reportTypes: [{id: 'track', name: this.$t('test_track.test_track')}],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openCard(type) {
|
||||
if(type === 'trackTestCase'){
|
||||
this.testCaseTrendDrawer = true;
|
||||
}else if(type === 'countTestCase'){
|
||||
this.testCaseCountDrawer = true;
|
||||
}
|
||||
},
|
||||
close() {
|
||||
this.testCaseTrendDrawer = false;
|
||||
this.testCaseCountDrawer = false;
|
||||
},
|
||||
saveReport(){
|
||||
if(this.testCaseTrendDrawer){
|
||||
this.$refs.testAnalysisContainer.saveReport();
|
||||
}else if(this.testCaseCountDrawer){
|
||||
this.$refs.testCaseCountContainer.saveReport();
|
||||
}
|
||||
},
|
||||
selectAndSaveReport(){
|
||||
if(this.testCaseTrendDrawer){
|
||||
this.$refs.testAnalysisContainer.selectAndSaveReport();
|
||||
}else if(this.testCaseCountDrawer){
|
||||
this.$refs.testCaseCountContainer.selectAndSaveReport();
|
||||
}
|
||||
},
|
||||
initHistoryReportId(reportId){
|
||||
this.historyReportId = reportId;
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ms-span {
|
||||
margin: 10px 10px 0px
|
||||
}
|
||||
|
||||
.tip {
|
||||
float: left;
|
||||
font-size: 14px;
|
||||
border-radius: 2px;
|
||||
border-left: 2px solid #783887;
|
||||
margin: 10px 20px 0px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,138 @@
|
|||
<template>
|
||||
<div class="ms-content">
|
||||
<el-row>
|
||||
<el-col :span="4">
|
||||
<el-card :body-style="{ padding: '0px' }" class="ms-col" @click.native="openCard('trackTestCase')">
|
||||
<img src="../../../assets/track.jpg" class="image">
|
||||
<div style="padding: 10px;">
|
||||
<span>{{$t('commons.report_statistics.test_case_analysis')}}</span>
|
||||
<div class="bottom clearfix">
|
||||
<time class="time">{{$t('commons.report_statistics.test_case_activity')}}</time>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-card :body-style="{ padding: '0px' }" class="ms-col" @click.native="openCard('countTestCase')">
|
||||
<img src="../../../assets/track.jpg" class="image">
|
||||
<div style="padding: 10px;">
|
||||
<span>{{$t('commons.report_statistics.test_case_count')}}</span>
|
||||
<div class="bottom clearfix">
|
||||
<time class="time">{{$t('commons.report_statistics.test_case_count_activity')}}</time>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-card :body-style="{ padding: '0px' }" class="ms-col">
|
||||
<img src="../../../assets/other.png" class="image">
|
||||
<div style="padding: 10px;">
|
||||
<span>预留模块敬请期待</span>
|
||||
<div class="bottom clearfix">
|
||||
<time class="time">{{$t('commons.report_statistics.test_case_activity')}}</time>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-card :body-style="{ padding: '0px' }" class="ms-col">
|
||||
<img src="../../../assets/other.png" class="image">
|
||||
<div style="padding: 10px;">
|
||||
<span>预留模块敬请期待</span>
|
||||
<div class="bottom clearfix">
|
||||
<time class="time">{{$t('commons.report_statistics.test_case_activity')}}</time>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-card :body-style="{ padding: '0px' }" class="ms-col">
|
||||
<img src="../../../assets/other.png" class="image">
|
||||
<div style="padding: 10px;">
|
||||
<span>预留模块敬请期待</span>
|
||||
<div class="bottom clearfix">
|
||||
<time class="time">{{$t('commons.report_statistics.test_case_activity')}}</time>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-card :body-style="{ padding: '0px' }" class="ms-col">
|
||||
<img src="../../../assets/other.png" class="image">
|
||||
<div style="padding: 10px;">
|
||||
<span>预留模块敬请期待</span>
|
||||
<div class="bottom clearfix">
|
||||
<time class="time">{{$t('commons.report_statistics.test_case_activity')}}</time>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {hasPermission} from "@/common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "ReportCard",
|
||||
components: {},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
openCard(type) {
|
||||
if (!hasPermission('PROJECT_REPORT_ANALYSIS:READ')) {
|
||||
this.$warning("无查看权限!");
|
||||
return;
|
||||
}
|
||||
this.$emit('openCard', type);
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.time {
|
||||
font-size: 13px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
margin-top: 13px;
|
||||
line-height: 12px;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 0;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.image {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.clearfix:before,
|
||||
.clearfix:after {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.clearfix:after {
|
||||
clear: both
|
||||
}
|
||||
|
||||
.ms-col {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.ms-content {
|
||||
padding: 15px 10px 15px 15px;
|
||||
}
|
||||
|
||||
.ms-col:hover {
|
||||
cursor: pointer;
|
||||
border-color: #783887;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,86 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-tabs v-model="activeName">
|
||||
<el-tab-pane :label="$t('commons.report_statistics.report_data.all_report')" name="allReport">
|
||||
<history-report-data-card :report-data="allReportData" :show-options-button="false" @deleteReport="deleteReport" @selectReport="selectReport"/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('commons.report_statistics.report_data.my_report')" name="myReport">
|
||||
<history-report-data-card :report-data="myReportData" :show-options-button="true" @deleteReport="deleteReport" @selectReport="selectReport"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getCurrentProjectID,getCurrentUserId} from "@/common/js/utils";
|
||||
import HistoryReportDataCard from "./compose/HistoryReportDataCard";
|
||||
export default {
|
||||
name: "HistoryReportData",
|
||||
components: {HistoryReportDataCard},
|
||||
data() {
|
||||
return {
|
||||
activeName: 'allReport',
|
||||
allReportData: [],
|
||||
myReportData: [],
|
||||
}
|
||||
},
|
||||
props:{
|
||||
reportType:String
|
||||
},
|
||||
created(){
|
||||
this.initReportData();
|
||||
},
|
||||
watch :{
|
||||
activeName(){
|
||||
this.initReportData();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initReportData(){
|
||||
let projectId = getCurrentProjectID();
|
||||
let userId = getCurrentUserId();
|
||||
this.allReportData = [];
|
||||
this.myReportData = [];
|
||||
|
||||
let paramsObj = {
|
||||
projectId:getCurrentProjectID(),
|
||||
reportType:this.reportType,
|
||||
};
|
||||
this.$post('/history/report/selectByParams',paramsObj, response => {
|
||||
let allData = response.data;
|
||||
allData.forEach(item => {
|
||||
if(item){
|
||||
this.allReportData.push(item);
|
||||
if(item.createUser === userId){
|
||||
this.myReportData.push(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
deleteReport(deleteId){
|
||||
let paramObj = {
|
||||
id:deleteId
|
||||
}
|
||||
this.$post('/history/report/deleteByParam',paramObj, response => {
|
||||
this.initReportData();
|
||||
});
|
||||
this.$emit("removeHistoryReportId");
|
||||
},
|
||||
selectReport(id){
|
||||
this.$emit("selectReport",id);
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.historyCard{
|
||||
border: 0px;
|
||||
}
|
||||
/deep/ .el-card__header{
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,115 @@
|
|||
<template>
|
||||
<div class="ms-header">
|
||||
<el-row>
|
||||
<div class="ms-div">{{title}}</div>
|
||||
<div class="ms-header-right">
|
||||
<el-button type="primary" v-if="isSaveAsButtonShow" size="mini" @click="handleSaveAs" :disabled="readOnly">{{ $t('commons.save_as') }}<i class="el-icon-files el-icon--right"></i></el-button>
|
||||
<el-button type="primary" v-if="isSaveButtonShow" size="mini" @click="handleSave" :disabled="readOnly">{{ $t('commons.save') }}<i class="el-icon-files el-icon--right"></i></el-button>
|
||||
<el-button type="" size="mini" @click="handleExport" :disabled="readOnly">{{ $t('report.export') }}<i class="el-icon-download el-icon--right"></i></el-button>
|
||||
<span class="ms-span">|</span>
|
||||
<i class="el-icon-close report-alt-ico" @click="close"/>
|
||||
</div>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {exportPdf, hasPermission} from "@/common/js/utils";
|
||||
import html2canvas from 'html2canvas';
|
||||
|
||||
export default {
|
||||
name: "ReportHeader",
|
||||
components: {},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
props:{
|
||||
title:String,
|
||||
historyReportId:String,
|
||||
},
|
||||
created() {
|
||||
},
|
||||
computed: {
|
||||
readOnly() {
|
||||
return !hasPermission('PROJECT_REPORT_ANALYSIS:READ+EXPORT');
|
||||
},
|
||||
isSaveAsButtonShow(){
|
||||
if(!this.historyReportId || this.historyReportId === null || this.historyReportId === ''){
|
||||
return false;
|
||||
}else {
|
||||
if(hasPermission('PROJECT_REPORT_ANALYSIS:READ+CREATE')){
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
isSaveButtonShow(){
|
||||
if(hasPermission('PROJECT_REPORT_ANALYSIS:READ+UPDATE')){
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleExport() {
|
||||
let name = this.title;
|
||||
this.$nextTick(function () {
|
||||
setTimeout(() => {
|
||||
html2canvas(document.getElementById('reportAnalysis'), {
|
||||
scale: 2
|
||||
}).then(function (canvas) {
|
||||
exportPdf(name, [canvas]);
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
},
|
||||
handleSave(){
|
||||
this.$emit("saveReport");
|
||||
},
|
||||
handleSaveAs(){
|
||||
this.$emit("selectAndSaveReport");
|
||||
},
|
||||
close() {
|
||||
this.$emit('closePage');
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ms-header {
|
||||
border-bottom: 1px solid #E6E6E6;
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
.ms-div {
|
||||
float: left;
|
||||
margin-left: 20px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.ms-span {
|
||||
margin: 0px 10px 10px;
|
||||
}
|
||||
|
||||
.ms-header-right {
|
||||
float: right;
|
||||
/*width: 320px;*/
|
||||
margin-bottom: 10px;
|
||||
margin-top: 10px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.report-alt-ico {
|
||||
font-size: 17px;
|
||||
top: auto;
|
||||
}
|
||||
|
||||
.report-alt-ico:hover {
|
||||
color: black;
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,86 @@
|
|||
<template>
|
||||
<div v-if="loadIsOver" v-loading="loading">
|
||||
<el-card class="historyCard" v-for="item in reportData" :key="item.id">
|
||||
<div slot="header">
|
||||
<li style="color:var(--count_number); font-size: 18px">
|
||||
<el-input v-if="item.isEdit === 'edit'" size="mini" @blur="updateReport(item)" v-model="item.name"/>
|
||||
<el-link v-if="item.isEdit !== 'edit'" type="info" @click="selectReport(item.id)" target="_blank" style="color:#303133; font-size: 14px">
|
||||
{{ item.name }}
|
||||
</el-link>
|
||||
<el-button v-if="showOptionsButton && item.isEdit !== 'edit'" style="float: right; padding: 3px 0; border: 0px;margin-left: 5px" icon="el-icon-delete" size="mini" @click="deleteReport(item.id)"></el-button>
|
||||
<el-button v-if="showOptionsButton && item.isEdit !== 'edit'" style="float: right; padding: 3px 0; border: 0px" icon="el-icon-edit" size="mini" @click="renameReport(item)"></el-button>
|
||||
</li>
|
||||
</div>
|
||||
<div class="text item">
|
||||
<span>{{ item.createTime | timestampFormatDate }}</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "HistoryReportDataCard",
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
loadIsOver: true,
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
props:{
|
||||
reportData:Array,
|
||||
showOptionsButton:Boolean
|
||||
},
|
||||
watch:{
|
||||
reportData:{
|
||||
handler:function (){
|
||||
this.loading = false;
|
||||
},
|
||||
deep:true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
reload(){
|
||||
this.loadIsOver = false;
|
||||
this.$nextTick(() => {
|
||||
this.loadIsOver = true;
|
||||
})
|
||||
},
|
||||
deleteReport(id){
|
||||
this.loading = true;
|
||||
this.$emit("deleteReport",id);
|
||||
},
|
||||
renameReport(item){
|
||||
item.isEdit = 'edit';
|
||||
this.reload();
|
||||
},
|
||||
selectReport(id){
|
||||
this.$emit("selectReport",id);
|
||||
},
|
||||
updateReport(item){
|
||||
let obj = {
|
||||
name: item.name,
|
||||
id: item.id
|
||||
};
|
||||
this.$post("/history/report/updateReport", obj, response => {
|
||||
});
|
||||
item.isEdit = "";
|
||||
this.reload();
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.historyCard{
|
||||
border: 0px;
|
||||
}
|
||||
/deep/ .el-card__header{
|
||||
border: 0px;
|
||||
padding-bottom: 0px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,16 @@
|
|||
const reportForm = () => import('./ReportAnalysis');
|
||||
|
||||
export default {
|
||||
path: "/report",
|
||||
name: "report",
|
||||
redirect: "/report/home",
|
||||
components: {
|
||||
content: reportForm
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'home',
|
||||
name: 'reportHome',
|
||||
},
|
||||
]
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
<template>
|
||||
<div>
|
||||
|
||||
<el-container v-loading="loading" id="reportAnalysis" style="overflow: scroll">
|
||||
<el-container class="ms-row">
|
||||
<el-aside v-if="!isHide" :width="!isHide ?'235px':'0px'" :style="{ 'max-height': h-50 + 'px', 'margin-left': '5px'}" >
|
||||
<history-report-data report-type="TEST_CASE_COUNT"
|
||||
@selectReport="selectReport" @removeHistoryReportId="removeHistoryReportId"
|
||||
ref="historyReport"/>
|
||||
</el-aside>
|
||||
<el-main class="ms-main" style="padding: 0px 5px 0px">
|
||||
<div>
|
||||
<test-case-count-chart @hidePage="hidePage" @orderCharts="orderCharts" ref="analysisChart"
|
||||
:chart-width="chartWidth" :load-option="loadOption" :pie-option="pieOption"/>
|
||||
</div>
|
||||
<div class="ms-row" v-if="!isHide">
|
||||
<test-case-count-table :group-name="getGroupNameStr(options.xaxis)" :show-coloums="options.yaxis" :tableData="tableData"/>
|
||||
</div>
|
||||
</el-main>
|
||||
<el-aside v-if="!isHide" style="height: 100%" :width="!isHide ?'485px':'0px'">
|
||||
<test-case-count-filter @filterCharts="filterCharts" ref="countFilter"/>
|
||||
</el-aside>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TestCaseCountChart from "./chart/TestCaseCountChart";
|
||||
import TestCaseCountTable from "@/business/components/reportstatistics/testCaseCount/table/TestCaseCountTable";
|
||||
import TestCaseCountFilter from "./filter/TestCaseCountFilter";
|
||||
import {exportPdf,getCurrentProjectID} from "@/common/js/utils";
|
||||
import html2canvas from 'html2canvas';
|
||||
import HistoryReportData from "../base/HistoryReportData";
|
||||
|
||||
export default {
|
||||
name: "TestCaseCountContainer",
|
||||
components: {TestCaseCountChart, TestCaseCountTable, TestCaseCountFilter, HistoryReportData},
|
||||
data() {
|
||||
return {
|
||||
isHide: false,
|
||||
loading: false,
|
||||
options: {},
|
||||
chartWidth: 0,
|
||||
tableHeight: 300,
|
||||
loadOption: {
|
||||
legend: {},
|
||||
xAxis: {},
|
||||
yAxis: {},
|
||||
label: {},
|
||||
tooltip: {},
|
||||
series: []
|
||||
},
|
||||
pieOption: {
|
||||
legend: {},
|
||||
label: {},
|
||||
tooltip: {},
|
||||
series: [],
|
||||
title: [],
|
||||
},
|
||||
|
||||
tableData: [],
|
||||
h: document.documentElement.clientHeight - 40,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleExport() {
|
||||
let name = this.$t('commons.report_statistics.test_case_analysis');
|
||||
this.$nextTick(function () {
|
||||
setTimeout(() => {
|
||||
html2canvas(document.getElementById('reportAnalysis'), {
|
||||
scale: 2
|
||||
}).then(function (canvas) {
|
||||
exportPdf(name, [canvas]);
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
},
|
||||
hidePage(isHide) {
|
||||
this.isHide = isHide;
|
||||
},
|
||||
close() {
|
||||
this.$emit('closePage');
|
||||
},
|
||||
init(opt) {
|
||||
this.loading = true;
|
||||
this.options = opt;
|
||||
this.$post(' /report/test/case/count/getReport', opt, response => {
|
||||
let data = response.data.barChartDTO;
|
||||
let pieData = response.data.pieChartDTO;
|
||||
let selectTableData = response.data.tableDTOs;
|
||||
this.initPic(data,pieData,selectTableData);
|
||||
|
||||
},error => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
initPic(barData,pieData,selectTableData){
|
||||
this.loading = true;
|
||||
if (barData) {
|
||||
this.loadOption.legend = barData.legend;
|
||||
this.loadOption.xAxis = barData.xaxis;
|
||||
this.loadOption.xaxis = barData.xaxis;
|
||||
this.loadOption.series = barData.series;
|
||||
this.loadOption.grid = {
|
||||
bottom: '75px',//距离下边距
|
||||
};
|
||||
this.loadOption.series.forEach(item => {
|
||||
item.type = this.$refs.analysisChart.chartType;
|
||||
});
|
||||
}
|
||||
if (pieData) {
|
||||
this.pieOption.legend = pieData.legend;
|
||||
this.pieOption.series = pieData.series;
|
||||
this.pieOption.title = pieData.title;
|
||||
this.pieOption.grid = {
|
||||
bottom: '75px',//距离下边距
|
||||
};
|
||||
if (pieData.width) {
|
||||
this.pieOption.width = pieData.width;
|
||||
this.chartWidth = pieData.width;
|
||||
}
|
||||
this.pieOption.series.forEach(item => {
|
||||
item.type = this.$refs.analysisChart.chartType;
|
||||
});
|
||||
}
|
||||
if (selectTableData) {
|
||||
this.tableData = selectTableData;
|
||||
}
|
||||
this.loading = false;
|
||||
this.$refs.analysisChart.reload();
|
||||
},
|
||||
filterCharts(opt) {
|
||||
this.init(opt);
|
||||
},
|
||||
orderCharts(order) {
|
||||
this.options.order = order;
|
||||
this.filterCharts(this.options);
|
||||
},
|
||||
saveReport() {
|
||||
let obj = {};
|
||||
obj.projectId = getCurrentProjectID();
|
||||
obj.selectOption = JSON.stringify(this.options);
|
||||
let dataOptionObj = {
|
||||
loadOption: this.loadOption,
|
||||
pieOption: this.pieOption,
|
||||
tableData: this.tableData,
|
||||
};
|
||||
obj.dataOption = JSON.stringify(dataOptionObj);
|
||||
obj.reportType = 'TEST_CASE_COUNT';
|
||||
this.$post("/history/report/saveReport", obj, response => {
|
||||
this.$alert(this.$t('commons.save_success'));
|
||||
this.$refs.historyReport.initReportData();
|
||||
});
|
||||
},
|
||||
selectReport(selectId){
|
||||
if(selectId){
|
||||
this.loading = true;
|
||||
let paramObj = {
|
||||
id:selectId
|
||||
}
|
||||
this.$post('/history/report/selectById',paramObj, response => {
|
||||
let reportData = response.data;
|
||||
if(reportData){
|
||||
if(reportData.dataOption){
|
||||
let dataOptionObj = JSON.parse(reportData.dataOption);
|
||||
this.initPic(dataOptionObj.loadOption,dataOptionObj.pieOption,dataOptionObj.tableData);
|
||||
}
|
||||
if(reportData.selectOption){
|
||||
let selectOptionObj = JSON.parse(reportData.selectOption);
|
||||
this.$refs.countFilter.initSelectOption(selectOptionObj);
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
}
|
||||
}, (error) => {
|
||||
this.loading = false;
|
||||
});
|
||||
this.$emit('initHistoryReportId',selectId);
|
||||
}
|
||||
},
|
||||
removeHistoryReportId(){
|
||||
this.$emit('initHistoryReportId',"");
|
||||
},
|
||||
getGroupNameStr(groupName){
|
||||
if(groupName === 'creator') {
|
||||
return this.$t('commons.report_statistics.report_filter.select_options.creator');
|
||||
}else if(groupName === 'maintainer'){
|
||||
return this.$t('commons.report_statistics.report_filter.select_options.maintainer');
|
||||
}else if(groupName === 'casetype'){
|
||||
return this.$t('commons.report_statistics.report_filter.select_options.case_type');
|
||||
}else if(groupName === 'casestatus'){
|
||||
return this.$t('commons.report_statistics.report_filter.select_options.case_status');
|
||||
}else if(groupName === 'caselevel'){
|
||||
return this.$t('commons.report_statistics.report_filter.select_options.case_level');
|
||||
}else {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
selectAndSaveReport(){
|
||||
let opt = this.$refs.countFilter.getOption();
|
||||
this.options = opt;
|
||||
this.saveReport();
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ms-row {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
/deep/ .el-main {
|
||||
padding: 0px 20px 0px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,284 @@
|
|||
<template>
|
||||
<div v-loading="loading">
|
||||
<el-card class="ms-test-chart" :style="{ width: w+'px', height: h + 'px'}" ref="msDrawer">
|
||||
<el-row class="ms-row">
|
||||
<p class="tip"><span style="margin-left: 5px"></span> {{$t('commons.report_statistics.chart')}} </p>
|
||||
<div class="ms-test-chart-header">
|
||||
<el-dropdown @command="exportCommand" :hide-on-click="false">
|
||||
<span class="el-dropdown-link">
|
||||
{{ $t('commons.export') }}<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="jpg">JPG</el-dropdown-item>
|
||||
<el-dropdown-item command="png">PNG</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
<span style="margin: 0px 10px 10px">|</span>
|
||||
<el-select v-model="chartType" class="ms-col-type" size="mini" style="width: 100px" @change="generateOption">
|
||||
<el-option :key="t.id" :value="t.id" :label="t.name" v-for="t in charts"/>
|
||||
</el-select>
|
||||
<span style="margin: 0px 10px 10px">|</span>
|
||||
<el-select v-model="order" class="ms-col-type" size="mini" style="width: 120px" @change="orderCharts">
|
||||
<el-option :key="t.id" :value="t.id" :label="t.name" v-for="t in orders"/>
|
||||
</el-select>
|
||||
<span style="margin: 0px 10px 10px">|</span>
|
||||
<font-awesome-icon v-if="!isFullScreen && showFullScreen" class="report-alt-ico" :icon="['fa', 'expand-alt']" size="lg" @click="fullScreen"/>
|
||||
<font-awesome-icon v-if="isFullScreen && showFullScreen" class="report-alt-ico" :icon="['fa', 'compress-alt']" size="lg" @click="unFullScreen"/>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-row style="overflow: auto">
|
||||
<ms-chart ref="chart1" v-if="!loading" :options="dataOption" :style="{width: chartWidthNumber+'px', height: (h-50) + 'px'}" class="chart-config" :autoresize="true" id="picChart"/>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import echarts from "echarts";
|
||||
import MsChart from "@/business/components/common/chart/MsChart";
|
||||
|
||||
export default {
|
||||
name: "TestCaseCountChart",
|
||||
components: {MsChart},
|
||||
props: {
|
||||
loadOption: {},
|
||||
pieOption: {},
|
||||
chartWidth:Number,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dataOption:{},
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: document.documentElement.clientWidth - 760,
|
||||
h: document.documentElement.clientHeight * 0.5 ,
|
||||
chartWidthNumber:document.documentElement.clientWidth - 760,
|
||||
isFullScreen: false,
|
||||
originalW: 100,
|
||||
originalH: 100,
|
||||
showFullScreen: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
// 头部部分
|
||||
chartType: "bar",
|
||||
charts: [
|
||||
{id: 'bar', name: this.$t('commons.report_statistics.bar')},
|
||||
{id: 'pie', name: this.$t('commons.report_statistics.pie')}
|
||||
],
|
||||
order: "",
|
||||
orders: [{id: '', name: '默认排序'},{id: 'desc', name: this.$t('commons.report_statistics.desc')}, {id: 'asc', name: this.$t('commons.report_statistics.asc')}],
|
||||
loading: false,
|
||||
options: {},
|
||||
pieItemOption:{
|
||||
dataset: [{
|
||||
source: [
|
||||
['Product', 'Sales', 'Price', 'Year'],
|
||||
['Cake', 123, 32, 2011],
|
||||
['Cereal', 231, 14, 2011],
|
||||
['Tofu', 235, 5, 2011],
|
||||
['Dumpling', 341, 25, 2011],
|
||||
['Biscuit', 122, 29, 2011],
|
||||
['Cake', 143, 30, 2012],
|
||||
['Cereal', 201, 19, 2012],
|
||||
['Tofu', 255, 7, 2012],
|
||||
['Dumpling', 241, 27, 2012],
|
||||
['Biscuit', 102, 34, 2012],
|
||||
['Cake', 153, 28, 2013],
|
||||
['Cereal', 181, 21, 2013],
|
||||
['Tofu', 395, 4, 2013],
|
||||
['Dumpling', 281, 31, 2013],
|
||||
['Biscuit', 92, 39, 2013],
|
||||
['Cake', 223, 29, 2014],
|
||||
['Cereal', 211, 17, 2014],
|
||||
['Tofu', 345, 3, 2014],
|
||||
['Dumpling', 211, 35, 2014],
|
||||
['Biscuit', 72, 24, 2014],
|
||||
],
|
||||
}, {
|
||||
transform: {
|
||||
type: 'filter',
|
||||
config: { dimension: 'Year', value: 2011 }
|
||||
},
|
||||
}, {
|
||||
transform: {
|
||||
type: 'filter',
|
||||
config: { dimension: 'Year', value: 2012 }
|
||||
}
|
||||
}, {
|
||||
transform: {
|
||||
type: 'filter',
|
||||
config: { dimension: 'Year', value: 2013 }
|
||||
}
|
||||
}],
|
||||
series: [{
|
||||
type: 'pie', radius: 50, center: ['50%', '25%'],
|
||||
datasetIndex: 1
|
||||
}, {
|
||||
type: 'pie', radius: 50, center: ['50%', '50%'],
|
||||
datasetIndex: 2
|
||||
}, {
|
||||
type: 'pie', radius: 50, center: ['50%', '75%'],
|
||||
datasetIndex: 3
|
||||
}],
|
||||
media: [{
|
||||
query: { minAspectRatio: 1 },
|
||||
option: {
|
||||
series: [
|
||||
{ center: ['25%', '50%'] },
|
||||
{ center: ['50%', '50%'] },
|
||||
{ center: ['75%', '50%'] }
|
||||
]
|
||||
}
|
||||
}, {
|
||||
option: {
|
||||
series: [
|
||||
{ center: ['50%', '25%'] },
|
||||
{ center: ['50%', '50%'] },
|
||||
{ center: ['50%', '75%'] }
|
||||
]
|
||||
}
|
||||
}]
|
||||
},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.dataOption = this.loadOption;
|
||||
},
|
||||
watch:{
|
||||
chartWidth(){
|
||||
this.countChartWidth();
|
||||
},
|
||||
chartType(){
|
||||
this.countChartWidth();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
countChartWidth(){
|
||||
if(this.chartWidth === 0 || this.chartType === 'bar'){
|
||||
this.chartWidthNumber = this.w;
|
||||
}else {
|
||||
this.chartWidthNumber = this.chartWidth;
|
||||
}
|
||||
},
|
||||
orderCharts() {
|
||||
this.$emit('orderCharts', this.order);
|
||||
},
|
||||
generateOption() {
|
||||
if(this.chartType === 'pie'){
|
||||
this.dataOption = this.pieOption;
|
||||
}else {
|
||||
this.dataOption = this.loadOption;
|
||||
}
|
||||
this.dataOption.series.forEach(item => {
|
||||
item.type = this.chartType;
|
||||
})
|
||||
this.reload();
|
||||
},
|
||||
reload() {
|
||||
this.loading = true
|
||||
this.$nextTick(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
fullScreen() {
|
||||
this.originalW = this.w;
|
||||
this.originalH = this.h;
|
||||
this.w = document.body.clientWidth - 50;
|
||||
this.h = document.body.clientHeight;
|
||||
this.isFullScreen = true;
|
||||
this.$emit('hidePage', true);
|
||||
},
|
||||
unFullScreen() {
|
||||
this.w = this.originalW;
|
||||
this.h = this.originalH;
|
||||
this.isFullScreen = false;
|
||||
this.$emit('hidePage', false);
|
||||
},
|
||||
exportCommand(command){
|
||||
let fileName = 'report_pic.'+command;
|
||||
if (document.getElementById('picChart')) {
|
||||
let chartsCanvas = document.getElementById('picChart').querySelectorAll('canvas')[0]
|
||||
let mime = 'image/png';
|
||||
if(command === 'jpg'){
|
||||
mime = 'image/jpg';
|
||||
}
|
||||
if (chartsCanvas) {
|
||||
// toDataURL()是canvas对象的一种方法,用于将canvas对象转换为base64位编码
|
||||
let imageUrl = chartsCanvas && chartsCanvas.toDataURL(mime)
|
||||
if (navigator.userAgent.indexOf('Trident') > -1) {
|
||||
// IE11
|
||||
let arr = imageUrl.split(',')
|
||||
// atob() 函数对已经使用base64编码编码的数据字符串进行解码
|
||||
let bstr = atob(arr[1])
|
||||
let bstrLen = bstr.length
|
||||
// Uint8Array, 开辟 8 位无符号整数值的类型化数组。内容将初始化为 0
|
||||
let u8arr = new Uint8Array(bstrLen)
|
||||
while (bstrLen--) {
|
||||
// charCodeAt() 方法可返回指定位置的字符的 Unicode 编码
|
||||
u8arr[bstrLen] = bstr.charCodeAt(bstrLen)
|
||||
}
|
||||
// msSaveOrOpenBlob 方法允许用户在客户端上保存文件,方法如同从 Internet 下载文件,这是此类文件保存到“下载”文件夹的原因
|
||||
window.navigator.msSaveOrOpenBlob(new Blob([u8arr], {type: mime}), fileName );
|
||||
} else {
|
||||
// 其他浏览器
|
||||
let $a = document.createElement('a')
|
||||
$a.setAttribute('href', imageUrl)
|
||||
$a.setAttribute('download', fileName)
|
||||
$a.click()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.ms-test-chart-header {
|
||||
z-index: 999;
|
||||
width: 380px;
|
||||
float: right;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.report-alt-ico {
|
||||
font-size: 15px;
|
||||
margin: 0px 10px 0px;
|
||||
color: #8c939d;
|
||||
}
|
||||
|
||||
.report-alt-ico:hover {
|
||||
color: black;
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/deep/ .echarts {
|
||||
height: calc(100vh / 1.95);
|
||||
}
|
||||
|
||||
.tip {
|
||||
float: left;
|
||||
font-size: 14px;
|
||||
border-radius: 2px;
|
||||
border-left: 2px solid #783887;
|
||||
margin: 0px 20px 0px;
|
||||
}
|
||||
|
||||
.ms-row {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.chart-config {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/deep/ .el-card__body {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,401 @@
|
|||
<template>
|
||||
<div v-loading="loading">
|
||||
<el-card :style="{height: h + 'px'}" class="ms-card">
|
||||
<el-row style="padding-top: 10px">
|
||||
<p class="tip"><span style="margin-left: 5px"></span> {{ $t('commons.report_statistics.options') }}</p>
|
||||
</el-row>
|
||||
<el-row class="ms-row">
|
||||
<p>{{ $t('commons.report_statistics.report_filter.xaxis') }}</p>
|
||||
<el-select class="ms-http-select" size="small" v-model="option.xaxis" style="width: 100%">
|
||||
<el-option v-for="item in xAxisOptions" :key="item.id" :label="item.label" :value="item.id"/>
|
||||
</el-select>
|
||||
</el-row>
|
||||
<el-row class="ms-row">
|
||||
<p>{{ $t('commons.report_statistics.report_filter.yaxis') }}</p>
|
||||
<el-select class="ms-http-select" size="small" v-model="option.yaxis" multiple style="width: 100%">
|
||||
<el-option v-for="item in yAxisOptions" :key="item.id" :label="item.label" :value="item.id"/>
|
||||
</el-select>
|
||||
</el-row>
|
||||
<el-row class="ms-row">
|
||||
<p>{{ $t('commons.create_time')}}</p>
|
||||
<div style="width: 25%;float: left">
|
||||
<el-select class="ms-http-select" size="small" v-model="option.timeType" >
|
||||
<el-option v-for="item in timeTypeOptions" :key="item.id" :label="item.label" :value="item.id"/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div v-if="option.timeType === 'fixedTime'" style="width: 70%;margin-left: 20px;float: left">
|
||||
<el-date-picker
|
||||
size="small"
|
||||
v-model="option.times"
|
||||
type="datetimerange"
|
||||
value-format="timestamp"
|
||||
:range-separator="$t('api_monitor.to')"
|
||||
:start-placeholder="$t('commons.date.start_date')"
|
||||
:end-placeholder="$t('commons.date.end_date')"
|
||||
:picker-options="datePickerOptions"
|
||||
style="margin-left: 10px;width: 100%">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div v-if="option.timeType === 'dynamicTime'" style="width: 70%;margin-left: 20px;float: left">
|
||||
<span style="width: 20%">{{ $t('commons.report_statistics.report_filter.recently') }}</span>
|
||||
<el-select class="ms-http-select" size="small" v-model="option.timeFilter.timeRange" style="width: 30%;margin-left: 10px;width: 40%">
|
||||
<el-option v-for="item in timeRangeNumberMax" :key="item" :label="item" :value="item"/>
|
||||
</el-select>
|
||||
<el-select class="ms-http-select" size="small" v-model="option.timeFilter.timeRangeUnit"
|
||||
@change="timeRangeUnitChange"
|
||||
style="width: 30%;margin-left: 10px;width: 40%">
|
||||
<el-option v-for="item in timeRangeUnitOptions" :key="item.id" :label="item.label" :value="item.id"/>
|
||||
</el-select>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-row class="ms-row" style="margin-left: 0px;margin-right: 0px; margin-top: 20px">
|
||||
<el-collapse v-model="collapseActiveNames">
|
||||
<el-collapse-item :title="$t('commons.report_statistics.report_filter.more_options')" name="1">
|
||||
<el-container>
|
||||
<el-aside width="73px" style="overflow: hidden">
|
||||
<div v-if="option.filters.length > 1" style="height: 100%" id="moreOptionTypeDiv">
|
||||
<div class="top-line-box" :style="{ height:lineDivHeight+'px'}">
|
||||
</div>
|
||||
<div>
|
||||
<el-select class="ms-http-select" size="small" v-model="option.filterType" style="width: 70px">
|
||||
<el-option v-for="item in filterTypes" :key="item.id" :label="item.label" :value="item.id"/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="bottom-line-box" :style="{ height:lineDivHeight+'px'}">
|
||||
</div>
|
||||
</div>
|
||||
</el-aside>
|
||||
<el-main v-if="optionLoad" style="padding: 0px">
|
||||
<el-row v-for="filterItem in option.filters" :key="filterItem.id" style="margin-bottom: 5px">
|
||||
<el-col :span="24">
|
||||
<el-select style="width: 100px" class="ms-http-select" size="small" v-model="filterItem.type">
|
||||
<el-option v-for="item in getFilterOptionKey(filterItem.type)" :key="item.type" :label="item.name" :value="item.type"/>
|
||||
</el-select>
|
||||
<span style="margin-left:10px;margin-right:10px">{{ $t('commons.report_statistics.report_filter.belone') }}</span>
|
||||
|
||||
<el-select style="width:173px" :collapse-tags="true" class="ms-http-select" size="small" multiple filterable v-model="filterItem.values" v-if="getFilterOptions(filterItem.type).length > 0">
|
||||
<el-option v-for="itemOption in getFilterOptions(filterItem.type)" :key="itemOption.id" :label="itemOption.label" :value="itemOption.id"/>
|
||||
</el-select>
|
||||
<el-input style="width:173px" v-model="filterItem.value" size="small" v-else ></el-input>
|
||||
<el-button @click="addFilterOptions(filterItem.type)"
|
||||
@keydown.enter.native.prevent
|
||||
type="primary"
|
||||
icon="el-icon-plus"
|
||||
circle
|
||||
style="color:white;padding: 0px 0.1px;width: 20px;height: 20px;margin-left:5px;"
|
||||
size="mini"/>
|
||||
<el-button @click="removeFilterOptions(filterItem.type)"
|
||||
@keydown.enter.native.prevent
|
||||
type="danger"
|
||||
icon="el-icon-minus"
|
||||
circle
|
||||
style="color:white;padding: 0px 0.1px;width: 20px;height: 20px;margin-left:5px;"
|
||||
size="mini"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</el-row>
|
||||
|
||||
|
||||
<el-row type="flex">
|
||||
<el-col style="height: 100%" :span="4" >
|
||||
|
||||
</el-col>
|
||||
<el-col :span="20">
|
||||
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row align="middle">
|
||||
<el-button style="margin-left: 200px;margin-top: 20px" type="primary" size="mini" @click="init">{{ $t('commons.confirm') }}</el-button>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getCurrentProjectID, getUUID} from "@/common/js/utils";
|
||||
import MsSelectTree from "@/business/components/common/select-tree/SelectTree";
|
||||
|
||||
export default {
|
||||
name: "TestAnalysisTable",
|
||||
components: {MsSelectTree},
|
||||
data() {
|
||||
return {
|
||||
collapseActiveNames: "",
|
||||
option: {
|
||||
xaxis: "creator",
|
||||
yaxis: ["testCase","apiCase","scenarioCase","loadCase"],
|
||||
timeType: "dynamicTime",
|
||||
projectId: getCurrentProjectID(),
|
||||
filterType: "And",
|
||||
timeFilter:{
|
||||
timeRange: 7,
|
||||
timeRangeUnit: "day",
|
||||
},
|
||||
times: [new Date().getTime() - 6 * 24 * 3600 * 1000, new Date().getTime()],
|
||||
filters:[
|
||||
{
|
||||
type:"",
|
||||
name:"",
|
||||
compType:"input",
|
||||
isShow:false,
|
||||
},
|
||||
],
|
||||
},
|
||||
h: document.documentElement.clientHeight + 80,
|
||||
lineDivHeight: 0,
|
||||
disabled: false,
|
||||
loading: false,
|
||||
optionLoad: true,
|
||||
result: {},
|
||||
items: [],
|
||||
modules: [],
|
||||
xAxisOptions: [
|
||||
{id: 'creator', label: this.$t('commons.report_statistics.report_filter.select_options.creator')},
|
||||
{id: 'maintainer', label: this.$t('commons.report_statistics.report_filter.select_options.maintainer')},
|
||||
{id: 'casetype', label: this.$t('commons.report_statistics.report_filter.select_options.case_type')},
|
||||
{id: 'casestatus', label: this.$t('commons.report_statistics.report_filter.select_options.case_status')},
|
||||
{id: 'caselevel', label: this.$t('commons.report_statistics.report_filter.select_options.case_level')},
|
||||
],
|
||||
yAxisOptions: [
|
||||
{id: 'testCase', label: this.$t('api_test.home_page.failed_case_list.table_value.case_type.functional')},
|
||||
{id: 'apiCase', label: this.$t('api_test.home_page.failed_case_list.table_value.case_type.api')},
|
||||
{id: 'scenarioCase', label: this.$t('api_test.home_page.failed_case_list.table_value.case_type.scene')},
|
||||
{id: 'loadCase', label: this.$t('api_test.home_page.failed_case_list.table_value.case_type.load')},
|
||||
],
|
||||
filterTypes: [
|
||||
{id: 'And', label: 'And'},
|
||||
{id: 'Or', label: 'Or'},
|
||||
],
|
||||
timeTypeOptions: [
|
||||
{id: 'fixedTime', label: this.$t('commons.report_statistics.report_filter.time_options.fixed_time')},
|
||||
{id: 'dynamicTime', label: this.$t('commons.report_statistics.report_filter.time_options.dynamic_time')},
|
||||
],
|
||||
timeRangeNumberMax: 31,
|
||||
timeRangeUnitOptions: [
|
||||
{id: 'day', label: this.$t('commons.report_statistics.report_filter.time_options.day')},
|
||||
{id: 'month', label: this.$t('commons.report_statistics.report_filter.time_options.month')},
|
||||
{id: 'year', label: this.$t('commons.report_statistics.report_filter.time_options.year')},
|
||||
],
|
||||
priorityFilters: [
|
||||
{id: 'P0', label: 'P0'},
|
||||
{id: 'P1', label: 'P1'},
|
||||
{id: 'P2', label: 'P2'},
|
||||
{id: 'P3', label: 'P3'}
|
||||
],
|
||||
moduleObj: {
|
||||
id: 'id',
|
||||
label: 'name',
|
||||
},
|
||||
moreOptionsSelectorKeys:[
|
||||
{
|
||||
type:"casetype",
|
||||
name:this.$t('commons.report_statistics.report_filter.select_options.case_type'),
|
||||
},
|
||||
{
|
||||
type:"creator",
|
||||
name:this.$t('commons.report_statistics.report_filter.select_options.creator'),
|
||||
},
|
||||
{
|
||||
type:"maintainer",
|
||||
name:this.$t('commons.report_statistics.report_filter.select_options.maintainer'),
|
||||
},
|
||||
{
|
||||
type:"casestatus",
|
||||
name:this.$t('commons.report_statistics.report_filter.select_options.case_status'),
|
||||
},
|
||||
{
|
||||
type:"caselevel",
|
||||
name:this.$t('commons.report_statistics.report_filter.select_options.case_level'),
|
||||
},
|
||||
],
|
||||
moreOptionsSelectorValues: {
|
||||
id: 'id',
|
||||
label: 'label',
|
||||
},
|
||||
datePickerOptions: {
|
||||
disabledDate: (time) => {
|
||||
let nowDate = new Date();
|
||||
let oneDay = 1000 * 60 * 60 * 24;
|
||||
let oneYearLater = new Date(nowDate.getTime() + (oneDay * 365));
|
||||
return time.getTime() > nowDate || time.getTime() > oneYearLater;//注意是||不是&&
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
this.initMoreOptionsSelectorValues();
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
watch: {
|
||||
option: {
|
||||
handler: function () {
|
||||
this.$nextTick(() => {
|
||||
this.lineDivHeight = 0;
|
||||
// let elem = document.getElementById("moreOptionTypeDiv");
|
||||
if(this.option.filters.length > 1){
|
||||
let countPageHeight = (this.option.filters.length)* 32 + (this.option.filters.length-1)*5;
|
||||
if(countPageHeight > 32){
|
||||
this.lineDivHeight = (countPageHeight-32)/2-11;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initSelectOption(opt){
|
||||
this.loading = true;
|
||||
this.option = opt;
|
||||
this.$nextTick(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
addFilterOptions: function (type){
|
||||
this.optionLoad = false;
|
||||
let otherOptionKeys = this.getFilterOptionKey("");
|
||||
if(otherOptionKeys.length > 0 && this.option.filters.length < 5) {
|
||||
let addOptions = {
|
||||
type: "",
|
||||
id: getUUID(),
|
||||
name: "",
|
||||
compType: "selector",
|
||||
isShow: false,
|
||||
itemOptions: this.priorityFilters,
|
||||
};
|
||||
this.option.filters.push(addOptions);
|
||||
} else {
|
||||
this.$alert(this.$t('commons.report_statistics.alert.cannot_add_more_options'));
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.optionLoad = true;
|
||||
});
|
||||
},
|
||||
getFilterOptions(type){
|
||||
let optionArray = [];
|
||||
if(this.moreOptionsSelectorValues && this.moreOptionsSelectorValues[type]){
|
||||
optionArray = this.moreOptionsSelectorValues[type];
|
||||
}
|
||||
return optionArray;
|
||||
},
|
||||
getFilterOptionKey(type){
|
||||
let optionArray = [];
|
||||
for(let i = 0; i < this.moreOptionsSelectorKeys.length; i++){
|
||||
let keyObj = this.moreOptionsSelectorKeys[i];
|
||||
let inOptions = false;
|
||||
if(keyObj.type !== type){
|
||||
for(let j = 0; j < this.option.filters.length; j ++){
|
||||
if(keyObj.type === this.option.filters[j].type){
|
||||
inOptions = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!inOptions){
|
||||
optionArray.push(keyObj);
|
||||
}
|
||||
}
|
||||
return optionArray;
|
||||
},
|
||||
removeFilterOptions: function (type){
|
||||
let removeOptionsIndex = -1;
|
||||
for(let index = 0; index < this.option.filters.length; index ++){
|
||||
let item = this.option.filters[index];
|
||||
if(item.type === type){
|
||||
removeOptionsIndex = index;
|
||||
}
|
||||
}
|
||||
if(removeOptionsIndex >= 0){
|
||||
this.option.filters.splice(removeOptionsIndex,1);
|
||||
}
|
||||
if(this.option.filters.length === 0){
|
||||
let addOptions = {
|
||||
type: "",
|
||||
id: getUUID(),
|
||||
name: "",
|
||||
compType: "selector",
|
||||
isShow: false,
|
||||
itemOptions: this.priorityFilters,
|
||||
};
|
||||
this.option.filters.push(addOptions);
|
||||
}
|
||||
},
|
||||
init: function () {
|
||||
this.$emit('filterCharts', this.option);
|
||||
},
|
||||
onTimeChange() {
|
||||
if (this.option.times[1] > new Date().getTime()) {
|
||||
this.$alert(this.$t('commons.report_statistics.alert.end_time_cannot_over_than_start_time'));
|
||||
}
|
||||
},
|
||||
initMoreOptionsSelectorValues() {
|
||||
let selectParam = {
|
||||
projectId:getCurrentProjectID()
|
||||
};
|
||||
this.$post('/report/test/case/count/initDatas',selectParam, response => {
|
||||
this.moreOptionsSelectorValues = response.data;
|
||||
});
|
||||
},
|
||||
timeRangeUnitChange(val){
|
||||
if(val === 'day'){
|
||||
this.timeRangeNumberMax = 31;
|
||||
}else if(val === 'month'){
|
||||
this.timeRangeNumberMax = 12;
|
||||
}else {
|
||||
this.timeRangeNumberMax = 1;
|
||||
}
|
||||
this.option.timeFilter.timeRange = 1;
|
||||
},
|
||||
getOption(){
|
||||
return this.option;
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.tip {
|
||||
float: left;
|
||||
font-size: 14px;
|
||||
border-radius: 2px;
|
||||
border-left: 2px solid #783887;
|
||||
margin: 0px 10px 0px;
|
||||
}
|
||||
|
||||
.ms-row {
|
||||
margin: 0px 10px 0px;
|
||||
}
|
||||
|
||||
.ms-card {
|
||||
width: 480px;
|
||||
}
|
||||
|
||||
.top-line-box{
|
||||
border-top: 1px solid;
|
||||
border-left: 1px solid;
|
||||
margin-left: 32px;
|
||||
margin-top: 10px;
|
||||
border-top-left-radius: 10px;
|
||||
}
|
||||
|
||||
.bottom-line-box{
|
||||
border-bottom: 1px solid;
|
||||
border-left: 1px solid;
|
||||
margin-left: 32px;
|
||||
border-bottom-left-radius: 10px;
|
||||
}
|
||||
|
||||
/deep/ .el-select__tags-text {
|
||||
display: inline-block;
|
||||
max-width: 50px;
|
||||
overflow: hidden;
|
||||
text-overflow:ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,113 @@
|
|||
<template>
|
||||
<div v-loading="loading" class="ms-div">
|
||||
<el-card :style="{ width: w+'px'}">
|
||||
<el-row style="padding-top: 10px">
|
||||
<p class="tip"><span style="margin-left: 5px"></span>{{$t('commons.report_statistics.excel')}} </p>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-table
|
||||
:data="tableData"
|
||||
:max-height="tableHeight"
|
||||
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
|
||||
row-key="id"
|
||||
border
|
||||
class="ms-table">
|
||||
<el-table-column
|
||||
prop="name"
|
||||
:label="groupName">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="allCount"
|
||||
label="总计">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="testCaseCount"
|
||||
:label="$t('api_test.home_page.failed_case_list.table_value.case_type.functional')"
|
||||
v-if="isShowColumn('testCase')"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="apiCaseCount"
|
||||
:label="$t('api_test.home_page.failed_case_list.table_value.case_type.api')"
|
||||
v-if="isShowColumn('apiCase')"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="scenarioCaseCount"
|
||||
:label="$t('api_test.home_page.failed_case_list.table_value.case_type.scene')"
|
||||
v-if="isShowColumn('scenarioCase')"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="loadCaseCount"
|
||||
:label="$t('api_test.home_page.failed_case_list.table_value.case_type.load')"
|
||||
v-if="isShowColumn('loadCase')"
|
||||
>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "TestAnalysisTable",
|
||||
components: {},
|
||||
props: {
|
||||
tableData: Array,
|
||||
groupName: String,
|
||||
showColoums: Array,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableHeight : "100px",
|
||||
w: document.documentElement.clientWidth - 760,
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getTableHeight();
|
||||
},
|
||||
methods: {
|
||||
isShowColumn(type){
|
||||
if(this.showColoums){
|
||||
return this.showColoums.findIndex(item => item=== type) >= 0;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
|
||||
},
|
||||
getTableHeight(){
|
||||
let countNumber = document.documentElement.clientHeight * 0.4 /1 - 140;
|
||||
countNumber = Math.ceil(countNumber);
|
||||
this.tableHeight = countNumber + 'px';
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.tip {
|
||||
float: left;
|
||||
font-size: 14px;
|
||||
border-radius: 2px;
|
||||
border-left: 2px solid #783887;
|
||||
margin: 0px 20px 0px;
|
||||
}
|
||||
|
||||
.ms-div {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.ms-table {
|
||||
width: 95%;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
/deep/ .el-card__body {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,168 @@
|
|||
<template>
|
||||
<div :style="{ height: h + 'px'}">
|
||||
<el-container v-loading="loading" id="reportAnalysis" style="overflow: scroll">
|
||||
<el-container class="ms-row">
|
||||
<el-aside :width="!isHide ?'235px':'0px'" style="margin-left: 5px; max-height: 843px">
|
||||
<history-report-data report-type="TEST_CASE_ANALYSIS"
|
||||
@selectReport="selectReport" @removeHistoryReportId="removeHistoryReportId"
|
||||
ref="historyReport"/>
|
||||
</el-aside>
|
||||
<el-main class="ms-main">
|
||||
<div>
|
||||
<test-analysis-chart @hidePage="hidePage" @orderCharts="orderCharts" ref="analysisChart" :load-option="loadOption"/>
|
||||
</div>
|
||||
<div class="ms-row" v-if="!isHide">
|
||||
<test-analysis-table :tableData="tableData"/>
|
||||
</div>
|
||||
</el-main>
|
||||
<el-aside :width="!isHide ?'485px':'0px'">
|
||||
<test-analysis-filter @filterCharts="filterCharts" ref="analysisFilter"/>
|
||||
</el-aside>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TestAnalysisChart from "./chart/TestAnalysisChart";
|
||||
import TestAnalysisTable from "./table/TestAnalysisTable";
|
||||
import TestAnalysisFilter from "./filter/TestAnalysisFilter";
|
||||
import {exportPdf, getCurrentProjectID} from "@/common/js/utils";
|
||||
import html2canvas from 'html2canvas';
|
||||
import HistoryReportData from "../base/HistoryReportData";
|
||||
|
||||
export default {
|
||||
name: "TestAnalysisContainer",
|
||||
components: {TestAnalysisChart, TestAnalysisTable, TestAnalysisFilter, HistoryReportData},
|
||||
data() {
|
||||
return {
|
||||
isHide: false,
|
||||
loading: false,
|
||||
options: {},
|
||||
loadOption: {
|
||||
legend: {},
|
||||
xAxis: {},
|
||||
yAxis: {},
|
||||
label: {},
|
||||
tooltip: {},
|
||||
series: []
|
||||
},
|
||||
tableData: [],
|
||||
h: document.documentElement.clientHeight - 40,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleExport() {
|
||||
let name = this.$t('commons.report_statistics.test_case_analysis');
|
||||
this.$nextTick(function () {
|
||||
setTimeout(() => {
|
||||
html2canvas(document.getElementById('reportAnalysis'), {
|
||||
scale: 2
|
||||
}).then(function (canvas) {
|
||||
exportPdf(name, [canvas]);
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
},
|
||||
hidePage(isHide) {
|
||||
this.isHide = isHide;
|
||||
},
|
||||
close() {
|
||||
this.$emit('closePage');
|
||||
},
|
||||
init(opt) {
|
||||
this.loading = true;
|
||||
this.options = opt;
|
||||
this.$post(' /report/test/analysis/getReport', opt, response => {
|
||||
let data = response.data.chartDTO;
|
||||
let tableDTOs = response.data.tableDTOs;
|
||||
this.initPic(data,tableDTOs);
|
||||
});
|
||||
},
|
||||
filterCharts(opt) {
|
||||
this.init(opt);
|
||||
},
|
||||
orderCharts(order) {
|
||||
this.options.order = order;
|
||||
this.filterCharts(this.options);
|
||||
},
|
||||
saveReport() {
|
||||
let obj = {};
|
||||
obj.projectId = getCurrentProjectID();
|
||||
obj.selectOption = JSON.stringify(this.options);
|
||||
let dataOptionObj = {
|
||||
loadOption: this.loadOption,
|
||||
pieOption: this.pieOption,
|
||||
tableData: this.tableData,
|
||||
};
|
||||
obj.dataOption = JSON.stringify(dataOptionObj);
|
||||
obj.reportType = 'TEST_CASE_ANALYSIS';
|
||||
this.$post("/history/report/saveReport", obj, response => {
|
||||
this.$alert(this.$t('commons.save_success'));
|
||||
this.$refs.historyReport.initReportData();
|
||||
});
|
||||
},
|
||||
initPic(loadOption,tableData){
|
||||
this.loading = true;
|
||||
if (loadOption) {
|
||||
this.loadOption.legend = loadOption.legend;
|
||||
this.loadOption.xAxis = loadOption.xAxis;
|
||||
this.loadOption.series = loadOption.series;
|
||||
this.loadOption.grid = {
|
||||
bottom: '75px',//距离下边距
|
||||
}
|
||||
this.loadOption.series.forEach(item => {
|
||||
item.type = this.$refs.analysisChart.chartType;
|
||||
})
|
||||
}
|
||||
if (tableData) {
|
||||
this.tableData = tableData;
|
||||
}
|
||||
this.loading = false;
|
||||
},
|
||||
selectReport(selectId){
|
||||
if(selectId){
|
||||
this.loading = true;
|
||||
let paramObj = {
|
||||
id:selectId
|
||||
}
|
||||
this.$post('/history/report/selectById',paramObj, response => {
|
||||
let reportData = response.data;
|
||||
if(reportData){
|
||||
if(reportData.dataOption){
|
||||
let dataOptionObj = JSON.parse(reportData.dataOption);
|
||||
this.initPic(dataOptionObj.loadOption,dataOptionObj.pieOption,dataOptionObj.tableData);
|
||||
}
|
||||
if(reportData.selectOption){
|
||||
let selectOptionObj = JSON.parse(reportData.selectOption);
|
||||
this.$refs.analysisFilter.initSelectOption(selectOptionObj);
|
||||
}
|
||||
}
|
||||
this.loading = false;
|
||||
}, (error) => {
|
||||
this.loading = false;
|
||||
});
|
||||
this.$emit('initHistoryReportId',selectId);
|
||||
}
|
||||
},
|
||||
removeHistoryReportId(){
|
||||
this.$emit('initHistoryReportId',"");
|
||||
},
|
||||
selectAndSaveReport(){
|
||||
let opt = this.$refs.analysisFilter.getOption();
|
||||
this.options = opt;
|
||||
this.saveReport();
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ms-row {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
/deep/ .el-main {
|
||||
padding: 0px 20px 0px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,143 @@
|
|||
<template>
|
||||
<div v-loading="loading">
|
||||
<el-card class="ms-test-chart" :style="{ width: w+'px', height: h + 'px'}" ref="msDrawer">
|
||||
<el-row class="ms-row">
|
||||
<p class="tip"><span style="margin-left: 5px"></span> {{$t('commons.report_statistics.chart')}} </p>
|
||||
<div class="ms-test-chart-header">
|
||||
<el-select v-model="chartType" class="ms-col-type" size="mini" style="width: 100px" @change="generateOption">
|
||||
<el-option :key="t.id" :value="t.id" :label="t.name" v-for="t in charts"/>
|
||||
</el-select>
|
||||
<span style="margin: 0px 10px 10px">|</span>
|
||||
<el-select v-model="order" class="ms-col-type" size="mini" style="width: 120px" @change="orderCharts">
|
||||
<el-option :key="t.id" :value="t.id" :label="t.name" v-for="t in orders"/>
|
||||
</el-select>
|
||||
<span style="margin: 0px 10px 10px">|</span>
|
||||
<font-awesome-icon v-if="!isFullScreen && showFullScreen" class="report-alt-ico" :icon="['fa', 'expand-alt']" size="lg" @click="fullScreen"/>
|
||||
<font-awesome-icon v-if="isFullScreen && showFullScreen" class="report-alt-ico" :icon="['fa', 'compress-alt']" size="lg" @click="unFullScreen"/>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<ms-chart ref="chart1" :options="loadOption" class="chart-config" :autoresize="true"/>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 这个引用不能删除,删除后图例不显示
|
||||
import echarts from "echarts";
|
||||
import MsChart from "@/business/components/common/chart/MsChart";
|
||||
|
||||
export default {
|
||||
name: "TestAnalysisChart",
|
||||
components: {MsChart},
|
||||
props: {
|
||||
loadOption: {},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: document.documentElement.clientWidth - 760,
|
||||
h: document.documentElement.clientHeight / 1.7,
|
||||
isFullScreen: false,
|
||||
originalW: 100,
|
||||
originalH: 100,
|
||||
showFullScreen: {
|
||||
type: Boolean,
|
||||
default() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
// 头部部分
|
||||
chartType: "line",
|
||||
charts: [{id: 'line', name: this.$t('commons.report_statistics.line')}, {id: 'bar', name: this.$t('commons.report_statistics.bar')}],
|
||||
order: "",
|
||||
orders: [{id: '', name: '默认排序'},{id: 'desc', name: this.$t('commons.report_statistics.desc')}, {id: 'asc', name: this.$t('commons.report_statistics.asc')}],
|
||||
loading: false,
|
||||
options: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
orderCharts() {
|
||||
this.$emit('orderCharts', this.order);
|
||||
},
|
||||
generateOption() {
|
||||
this.loadOption.series.forEach(item => {
|
||||
item.type = this.chartType;
|
||||
})
|
||||
this.reload();
|
||||
},
|
||||
reload() {
|
||||
this.loading = true
|
||||
this.$nextTick(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
fullScreen() {
|
||||
this.originalW = this.w;
|
||||
this.originalH = this.h;
|
||||
this.w = document.body.clientWidth - 50;
|
||||
this.h = document.body.clientHeight;
|
||||
this.isFullScreen = true;
|
||||
this.$emit('hidePage', true);
|
||||
},
|
||||
unFullScreen() {
|
||||
this.w = this.originalW;
|
||||
this.h = this.originalH;
|
||||
this.isFullScreen = false;
|
||||
this.$emit('hidePage', false);
|
||||
},
|
||||
getOptions(){
|
||||
return this.loadOption;
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.ms-test-chart-header {
|
||||
z-index: 999;
|
||||
width: 320px;
|
||||
float: right;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.report-alt-ico {
|
||||
font-size: 15px;
|
||||
margin: 0px 10px 0px;
|
||||
color: #8c939d;
|
||||
}
|
||||
|
||||
.report-alt-ico:hover {
|
||||
color: black;
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/deep/ .echarts {
|
||||
height: calc(100vh / 1.95);
|
||||
}
|
||||
|
||||
.tip {
|
||||
float: left;
|
||||
font-size: 14px;
|
||||
border-radius: 2px;
|
||||
border-left: 2px solid #783887;
|
||||
margin: 0px 20px 0px;
|
||||
}
|
||||
|
||||
.ms-row {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.chart-config {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/deep/ .el-card__body {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,225 @@
|
|||
<template>
|
||||
<div v-loading="loading">
|
||||
<el-card :style="{height: h + 'px'}" class="ms-card">
|
||||
<el-row style="padding-top: 10px">
|
||||
<p class="tip"><span style="margin-left: 5px"></span> {{$t('commons.report_statistics.options')}}</p>
|
||||
</el-row>
|
||||
<el-row class="ms-row">
|
||||
<p>{{$t('commons.report_statistics.type')}}</p>
|
||||
<el-checkbox v-model="option.createCase">{{$t('commons.report_statistics.add_case')}}</el-checkbox>
|
||||
<el-checkbox v-model="option.updateCase">{{$t('commons.report_statistics.change_case')}}</el-checkbox>
|
||||
</el-row>
|
||||
<el-row class="ms-row">
|
||||
<p> {{$t('api_monitor.date')}}</p>
|
||||
<el-date-picker
|
||||
size="small"
|
||||
v-model="option.times"
|
||||
type="datetimerange"
|
||||
value-format="timestamp"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:picker-options="datePickerOptions"
|
||||
style="width: 100%">
|
||||
</el-date-picker>
|
||||
</el-row>
|
||||
<el-row class="ms-row">
|
||||
<p>{{$t('commons.project')}}</p>
|
||||
<ms-select-tree size="small" :data="items" :default-key="projectDefaultKey" @getValue="setProjects" :obj="obj" clearable checkStrictly multiple ref="projectSelector"/>
|
||||
</el-row>
|
||||
<el-row class="ms-row">
|
||||
<p>{{$t('test_track.module.module')}}</p>
|
||||
<ms-select-tree size="small" :data="modules" :default-key="moduleDefaultKey" :disabled="disabled" @getValue="setModules" :obj="moduleObj" clearable checkStrictly multiple ref="moduleSelector"/>
|
||||
</el-row>
|
||||
<el-row class="ms-row">
|
||||
<p>{{$t('api_test.automation.case_level')}}</p>
|
||||
<el-select class="ms-http-select" size="small" v-model="option.prioritys" multiple style="width: 100%">
|
||||
<el-option v-for="item in priorityFilters" :key="item.id" :label="item.label" :value="item.id"/>
|
||||
</el-select>
|
||||
</el-row>
|
||||
<el-row class="ms-row">
|
||||
<p>{{$t('test_track.case.maintainer')}}</p>
|
||||
<ms-select-tree size="small" :data="maintainerOptions" :default-key="userDefaultKey" @getValue="setUsers" :obj="moduleObj" clearable checkStrictly multiple ref="userSelector"/>
|
||||
</el-row>
|
||||
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getCurrentProjectID} from "@/common/js/utils";
|
||||
import MsSelectTree from "@/business/components/common/select-tree/SelectTree";
|
||||
|
||||
export default {
|
||||
name: "TestAnalysisTable",
|
||||
components: {MsSelectTree},
|
||||
data() {
|
||||
return {
|
||||
option: {createCase: true, updateCase: true, projects: [], times: [new Date().getTime() - 6 * 24 * 3600 * 1000, new Date().getTime()]},
|
||||
h: document.documentElement.clientHeight + 80,
|
||||
disabled: false,
|
||||
loading: false,
|
||||
result: {},
|
||||
items: [],
|
||||
projectDefaultKey:[],
|
||||
moduleDefaultKey:[],
|
||||
userDefaultKey:[],
|
||||
modules: [],
|
||||
maintainerOptions: [],
|
||||
priorityFilters: [
|
||||
{id: 'P0', label: 'P0'},
|
||||
{id: 'P1', label: 'P1'},
|
||||
{id: 'P2', label: 'P2'},
|
||||
{id: 'P3', label: 'P3'}
|
||||
],
|
||||
syncReport: true,
|
||||
moduleObj: {
|
||||
id: 'id',
|
||||
label: 'name',
|
||||
},
|
||||
obj: {
|
||||
id: 'id',
|
||||
label: 'label',
|
||||
},
|
||||
datePickerOptions: {
|
||||
disabledDate: (time) => {
|
||||
let nowDate = new Date();
|
||||
let oneDay = 1000 * 60 * 60 * 24;
|
||||
let oneYearLater = new Date(nowDate.getTime() + (oneDay * 365));
|
||||
return time.getTime() > nowDate || time.getTime() > oneYearLater;//注意是||不是&&
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
this.initUsers();
|
||||
},
|
||||
watch: {
|
||||
option: {
|
||||
handler: function () {
|
||||
if(this.syncReport){
|
||||
this.$emit('filterCharts', this.option);
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initSelectOption(opt){
|
||||
if(opt){
|
||||
this.syncReport = false;
|
||||
this.loading = true;
|
||||
this.option = opt;
|
||||
if(opt.projects){
|
||||
this.projectDefaultKey = opt.projects;
|
||||
}else {
|
||||
this.projectDefaultKey = [];
|
||||
}
|
||||
if(opt.modules && this.projectDefaultKey.length === 1){
|
||||
this.moduleDefaultKey = opt.modules;
|
||||
}else {
|
||||
this.moduleDefaultKey = [];
|
||||
}
|
||||
if(opt.users){
|
||||
this.userDefaultKey = opt.users;
|
||||
}else {
|
||||
this.userDefaultKey = [];
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.loading = false;
|
||||
this.syncReport = true;
|
||||
});
|
||||
}
|
||||
},
|
||||
init: function () {
|
||||
this.result = this.$get("/project/listAll", response => {
|
||||
let projects = response.data;
|
||||
if (projects) {
|
||||
this.items = [];
|
||||
projects.forEach(item => {
|
||||
let data = {id: item.id, label: item.name};
|
||||
this.items.push(data);
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
onTimeChange() {
|
||||
if (this.option.times[1] > new Date().getTime()) {
|
||||
this.$error("结束时间不能超过当前时间");
|
||||
}
|
||||
},
|
||||
initModule() {
|
||||
this.result = this.$get("/case/node/list/" + this.option.projects[0], response => {
|
||||
this.modules = response.data;
|
||||
this.$refs.moduleSelector.setKeys(this.moduleDefaultKey);
|
||||
})
|
||||
},
|
||||
initUsers() {
|
||||
this.$post('/user/project/member/tester/list', {projectId: getCurrentProjectID()}, response => {
|
||||
this.maintainerOptions = response.data;
|
||||
});
|
||||
},
|
||||
setProjects(key, data) {//获取子组件值
|
||||
if(!key || key === ""){
|
||||
key = [];
|
||||
}
|
||||
this.option.projects = key;
|
||||
this.modules = [];
|
||||
if (key && key.length > 1) {
|
||||
this.moduleDefaultKey = [];
|
||||
this.disabled = true;
|
||||
} else {
|
||||
this.disabled = false;
|
||||
}
|
||||
if (this.option.projects && this.option.projects.length == 1) {
|
||||
this.initModule();
|
||||
}
|
||||
if(this.syncReport){
|
||||
this.$emit('filterCharts', this.option);
|
||||
}
|
||||
},
|
||||
setModules(key, data) {//获取子组件值
|
||||
if(!key || key === ""){
|
||||
key = [];
|
||||
}
|
||||
this.option.modules = key;
|
||||
if(this.syncReport){
|
||||
this.$emit('filterCharts', this.option);
|
||||
}
|
||||
},
|
||||
setUsers(key, data) {//获取子组件值
|
||||
if(!key || key === ""){
|
||||
key = [];
|
||||
}
|
||||
this.option.users = key;
|
||||
if(this.syncReport){
|
||||
this.$emit('filterCharts', this.option);
|
||||
}
|
||||
},
|
||||
getOption(){
|
||||
return this.option;
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.tip {
|
||||
float: left;
|
||||
font-size: 14px;
|
||||
border-radius: 2px;
|
||||
border-left: 2px solid #783887;
|
||||
margin: 0px 10px 0px;
|
||||
}
|
||||
|
||||
.ms-row {
|
||||
margin: 0px 10px 0px;
|
||||
}
|
||||
|
||||
.ms-card {
|
||||
width: 480px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,77 @@
|
|||
<template>
|
||||
<div v-loading="loading" class="ms-div">
|
||||
<el-card :style="{ width: w+'px'}">
|
||||
<el-row style="padding-top: 10px">
|
||||
<p class="tip"><span style="margin-left: 5px"></span>{{$t('commons.report_statistics.excel')}} </p>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-table
|
||||
:data="tableData"
|
||||
:height="h"
|
||||
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
|
||||
row-key="id"
|
||||
border
|
||||
class="ms-table">
|
||||
<el-table-column
|
||||
prop="name"
|
||||
:label="$t('api_monitor.date')"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="createCount"
|
||||
:label="$t('commons.report_statistics.add_case')"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="updateCount"
|
||||
sortable
|
||||
:label="$t('commons.report_statistics.change_case')">
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "TestAnalysisTable",
|
||||
components: {},
|
||||
props: {
|
||||
tableData: Array,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
w: document.documentElement.clientWidth - 760,
|
||||
h: document.body.clientHeight / 2.3 - 20,
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
methods: {},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.tip {
|
||||
float: left;
|
||||
font-size: 14px;
|
||||
border-radius: 2px;
|
||||
border-left: 2px solid #783887;
|
||||
margin: 0px 20px 0px;
|
||||
}
|
||||
|
||||
.ms-div {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.ms-table {
|
||||
width: 95%;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
/deep/ .el-card__body {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -1 +1 @@
|
|||
Subproject commit d99efd7e4f70846553444065fab8159e65035525
|
||||
Subproject commit e0da1d3ef611b0901e42520f6d68a04cabec4c08
|
|
@ -43,6 +43,7 @@ export default {
|
|||
annotation: 'Annotation',
|
||||
clear: 'Clear',
|
||||
save: 'Save',
|
||||
save_as: 'Save as',
|
||||
update: 'Update',
|
||||
save_success: 'Saved successfully',
|
||||
delete_success: 'Deleted successfully',
|
||||
|
|
|
@ -43,6 +43,7 @@ export default {
|
|||
annotation: '注释',
|
||||
clear: '清空',
|
||||
save: '保存',
|
||||
save_as: '另存为',
|
||||
update: '更新',
|
||||
save_success: '保存成功',
|
||||
delete_success: '删除成功',
|
||||
|
|
|
@ -43,6 +43,7 @@ export default {
|
|||
annotation: '註釋',
|
||||
clear: '清空',
|
||||
save: '保存',
|
||||
save_as: '另存為',
|
||||
update: '更新',
|
||||
save_success: '保存成功',
|
||||
delete_success: '刪除成功',
|
||||
|
|
Loading…
Reference in New Issue