From e02e7c726f9e8f552bf7489c30a0a0b7a61042b1 Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Mon, 30 Nov 2020 11:01:29 +0800 Subject: [PATCH 1/9] =?UTF-8?q?fix(=E6=B5=8B=E8=AF=95=E8=B7=9F=E8=B8=AA):?= =?UTF-8?q?=20=E7=9B=AE=E5=BD=95=E8=8A=82=E7=82=B9=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=BF=9D=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../track/service/TestCaseNodeService.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/backend/src/main/java/io/metersphere/track/service/TestCaseNodeService.java b/backend/src/main/java/io/metersphere/track/service/TestCaseNodeService.java index 6594536019..79d84fc311 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestCaseNodeService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestCaseNodeService.java @@ -372,7 +372,7 @@ public class TestCaseNodeService { public Map createNodes(List nodePaths, String projectId) { List nodeTrees = getNodeTreeByProjectId(projectId); Map pathMap = new HashMap<>(); - for(String item : nodePaths){ + for (String item : nodePaths) { if (item == null) { throw new ExcelException(Translator.get("test_case_module_not_null")); } @@ -590,6 +590,7 @@ public class TestCaseNodeService { /** * 测试用例同级模块排序 + * * @param ids 被拖拽模块相邻的前一个模块 id, * 被拖拽的模块 id, * 被拖拽模块相邻的后一个模块 id @@ -635,10 +636,11 @@ public class TestCaseNodeService { /** * 按照指定排序方式获取同级模块的列表 + * * @param projectId 所属项目 id - * @param level node level - * @param parentId node parent id - * @param order pos 排序方式 + * @param level node level + * @param parentId node parent id + * @param order pos 排序方式 * @return 按照指定排序方式排序的同级模块列表 */ private List getPos(String projectId, int level, String parentId, String order) { @@ -654,9 +656,10 @@ public class TestCaseNodeService { /** * 刷新同级模块的 pos 值 + * * @param projectId project id - * @param level node level - * @param parentId node parent id + * @param level node level + * @param parentId node parent id */ private void refreshPos(String projectId, int level, String parentId) { List nodes = getPos(projectId, level, parentId, "pos asc"); @@ -675,14 +678,15 @@ public class TestCaseNodeService { /** * 获得同级模块下一个 pos 值 + * * @param projectId project id - * @param level node level - * @param parentId node parent id + * @param level node level + * @param parentId node parent id * @return 同级模块下一个 pos 值 */ private double getNextLevelPos(String projectId, int level, String parentId) { List list = getPos(projectId, level, parentId, "pos desc"); - if (!CollectionUtils.isEmpty(list)) { + if (!CollectionUtils.isEmpty(list) && list.get(0) != null && list.get(0).getPos() != null) { return list.get(0).getPos() + 65536; } else { return 65536; From 3c05506204aac75535bb8d16138a0209e7d94f3f Mon Sep 17 00:00:00 2001 From: shiziyuan9527 Date: Mon, 30 Nov 2020 17:57:15 +0800 Subject: [PATCH 2/9] =?UTF-8?q?refactor(=E7=B3=BB=E7=BB=9F=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE):=20=E8=B0=83=E6=95=B4=E7=BC=BA=E9=99=B7=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=B9=B3=E5=8F=B0=E5=9B=BE=E6=A0=87=E5=A4=A7=E5=B0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/settings/organization/BugManagement.vue | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/frontend/src/business/components/settings/organization/BugManagement.vue b/frontend/src/business/components/settings/organization/BugManagement.vue index 670a4ff8cf..0c5a2c3bb7 100644 --- a/frontend/src/business/components/settings/organization/BugManagement.vue +++ b/frontend/src/business/components/settings/organization/BugManagement.vue @@ -10,7 +10,7 @@ Jira - Zentao + Zentao @@ -66,7 +66,12 @@ export default { } .platform { - height: 90px; + height: 80px; + vertical-align: middle +} + +.zentao_platform { + height: 100px; vertical-align: middle } From 8dc013927ce370a1cee8c8fe68f68b1aab99afb9 Mon Sep 17 00:00:00 2001 From: chenfanghang <20001117@qq.com> Date: Sat, 28 Nov 2020 23:58:30 +0800 Subject: [PATCH 3/9] =?UTF-8?q?feat(=E6=8E=A5=E5=8F=A3=E7=9B=91=E6=8E=A7):?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=93=8D=E5=BA=94=E6=97=B6=E9=97=B4=E4=B8=8E?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E7=9B=91=E6=8E=A7=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/ApiMonitorController.java | 55 ++++++ .../metersphere/api/dto/ApiMonitorSearch.java | 10 ++ .../api/dto/ApiResponseCodeMonitor.java | 20 +++ .../api/dto/ApiResponseTimeMonitor.java | 20 +++ .../api/service/APIMonitorService.java | 35 ++++ .../api/service/APIReportService.java | 51 ++++++ .../metersphere/base/domain/ApiDataView.java | 24 +++ .../base/mapper/ApiDataViewMapper.java | 23 +++ .../base/mapper/ApiDataViewMapper.xml | 77 ++++++++ .../db/migration/V47__api_data_view.sql | 12 ++ .../components/api/head/ApiHeaderMenus.vue | 5 + .../components/api/monitor/ApiMonitor.vue | 168 ++++++++++++++++++ .../api/monitor/ApiMonitorChart.vue | 46 +++++ .../api/monitor/ApiMonitorSearch.vue | 100 +++++++++++ .../components/ApiErrorMonitorChart.vue | 93 ++++++++++ .../ApiResponseTimeMonitorChart.vue | 64 +++++++ .../monitor/components/CommonMonitorChart.vue | 33 ++++ .../src/business/components/api/router.js | 12 +- frontend/src/common/js/ajax.js | 6 +- frontend/src/common/js/chart.js | 2 + frontend/src/common/js/format-utils.js | 36 ++++ frontend/src/i18n/en-US.js | 13 +- frontend/src/i18n/zh-CN.js | 13 +- frontend/src/i18n/zh-TW.js | 13 +- 24 files changed, 924 insertions(+), 7 deletions(-) create mode 100644 backend/src/main/java/io/metersphere/api/controller/ApiMonitorController.java create mode 100644 backend/src/main/java/io/metersphere/api/dto/ApiMonitorSearch.java create mode 100644 backend/src/main/java/io/metersphere/api/dto/ApiResponseCodeMonitor.java create mode 100644 backend/src/main/java/io/metersphere/api/dto/ApiResponseTimeMonitor.java create mode 100644 backend/src/main/java/io/metersphere/api/service/APIMonitorService.java create mode 100644 backend/src/main/java/io/metersphere/base/domain/ApiDataView.java create mode 100644 backend/src/main/java/io/metersphere/base/mapper/ApiDataViewMapper.java create mode 100644 backend/src/main/java/io/metersphere/base/mapper/ApiDataViewMapper.xml create mode 100644 backend/src/main/resources/db/migration/V47__api_data_view.sql create mode 100644 frontend/src/business/components/api/monitor/ApiMonitor.vue create mode 100644 frontend/src/business/components/api/monitor/ApiMonitorChart.vue create mode 100644 frontend/src/business/components/api/monitor/ApiMonitorSearch.vue create mode 100644 frontend/src/business/components/api/monitor/components/ApiErrorMonitorChart.vue create mode 100644 frontend/src/business/components/api/monitor/components/ApiResponseTimeMonitorChart.vue create mode 100644 frontend/src/business/components/api/monitor/components/CommonMonitorChart.vue diff --git a/backend/src/main/java/io/metersphere/api/controller/ApiMonitorController.java b/backend/src/main/java/io/metersphere/api/controller/ApiMonitorController.java new file mode 100644 index 0000000000..2384d0b7f2 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/controller/ApiMonitorController.java @@ -0,0 +1,55 @@ +package io.metersphere.api.controller; + +import io.metersphere.api.dto.ApiMonitorSearch; +import io.metersphere.api.dto.ApiResponseCodeMonitor; +import io.metersphere.api.dto.ApiResponseTimeMonitor; +import io.metersphere.api.service.APIMonitorService; +import io.metersphere.commons.constants.RoleConstants; +import org.apache.shiro.authz.annotation.Logical; +import org.apache.shiro.authz.annotation.RequiresRoles; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +@RestController +@RequestMapping(value = "/api/monitor") +@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER, RoleConstants.TEST_VIEWER}, logical = Logical.OR) +public class ApiMonitorController { + + @Resource + private APIMonitorService apiMonitorService; + + /** + * 查询所有接口 + */ + @GetMapping("/list") + public List apiList() { + return apiMonitorService.list(); + } + + + /** + * 查询响应时间 + */ + @GetMapping("/getResponseTime") + public List responseTimeData(@RequestHeader("apiUrl") String url, String startTime, String endTime) { + return apiMonitorService.getApiResponseTimeData(url, startTime, endTime); + } + + /** + * 查询状态码 + */ + @GetMapping("/getResponseCode") + public List responseCodeData(@RequestHeader("apiUrl") String url, String startTime, String endTime) { + return apiMonitorService.getApiResponseCodeData(url, startTime, endTime); + } + + /** + * 查询reportId + */ + @GetMapping("/getReportId") + public String searchReportId(@RequestHeader("apiUrl") String url, @RequestParam("startTime") String startTime) { + return apiMonitorService.getReportId(url, startTime); + } +} diff --git a/backend/src/main/java/io/metersphere/api/dto/ApiMonitorSearch.java b/backend/src/main/java/io/metersphere/api/dto/ApiMonitorSearch.java new file mode 100644 index 0000000000..9ed3e0fc31 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/ApiMonitorSearch.java @@ -0,0 +1,10 @@ +package io.metersphere.api.dto; + +import lombok.Data; + +@Data +public class ApiMonitorSearch { + + private String url; + +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/api/dto/ApiResponseCodeMonitor.java b/backend/src/main/java/io/metersphere/api/dto/ApiResponseCodeMonitor.java new file mode 100644 index 0000000000..8fc6c1bd10 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/ApiResponseCodeMonitor.java @@ -0,0 +1,20 @@ +package io.metersphere.api.dto; + +import lombok.Data; + +@Data +public class ApiResponseCodeMonitor { + + private String id; + + private String reportId; + + private String url; + + private String apiName; + + private String startTime; + + private String responseCode; + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/ApiResponseTimeMonitor.java b/backend/src/main/java/io/metersphere/api/dto/ApiResponseTimeMonitor.java new file mode 100644 index 0000000000..80ba42b930 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/ApiResponseTimeMonitor.java @@ -0,0 +1,20 @@ +package io.metersphere.api.dto; + +import lombok.Data; + +@Data +public class ApiResponseTimeMonitor { + + private String id; + + private String reportId; + + private String url; + + private String apiName; + + private String startTime; + + private String responseTime; + +} diff --git a/backend/src/main/java/io/metersphere/api/service/APIMonitorService.java b/backend/src/main/java/io/metersphere/api/service/APIMonitorService.java new file mode 100644 index 0000000000..d8e942a01a --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/service/APIMonitorService.java @@ -0,0 +1,35 @@ +package io.metersphere.api.service; + +import io.metersphere.api.dto.ApiMonitorSearch; +import io.metersphere.api.dto.ApiResponseCodeMonitor; +import io.metersphere.api.dto.ApiResponseTimeMonitor; +import io.metersphere.base.mapper.ApiDataViewMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; + +@Service +@Transactional(rollbackFor = Exception.class) +public class APIMonitorService { + + @Resource + private ApiDataViewMapper apiDataViewMapper; + + public List list() { + return apiDataViewMapper.selectAll(); + } + + public List getApiResponseTimeData(String apiUrl, String startTime, String endTime) { + return apiDataViewMapper.selectResponseTimeByUrl(apiUrl, startTime, endTime); + } + + public List getApiResponseCodeData(String apiUrl, String startTime, String endTime) { + return apiDataViewMapper.selectResponseCodeByUrl(apiUrl, startTime, endTime); + } + + public String getReportId(String apiUrl, String startTime) { + return apiDataViewMapper.selectReportIdByUrlAndStartTime(apiUrl, startTime); + } +} diff --git a/backend/src/main/java/io/metersphere/api/service/APIReportService.java b/backend/src/main/java/io/metersphere/api/service/APIReportService.java index cc4367eb8b..a8ce783493 100644 --- a/backend/src/main/java/io/metersphere/api/service/APIReportService.java +++ b/backend/src/main/java/io/metersphere/api/service/APIReportService.java @@ -1,17 +1,21 @@ package io.metersphere.api.service; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import io.metersphere.api.dto.APIReportResult; import io.metersphere.api.dto.DeleteAPIReportRequest; import io.metersphere.api.dto.QueryAPIReportRequest; import io.metersphere.api.jmeter.TestResult; import io.metersphere.base.domain.*; +import io.metersphere.base.mapper.ApiDataViewMapper; import io.metersphere.base.mapper.ApiTestReportDetailMapper; import io.metersphere.base.mapper.ApiTestReportMapper; import io.metersphere.base.mapper.ext.ExtApiTestReportMapper; import io.metersphere.commons.constants.APITestStatus; import io.metersphere.commons.constants.ReportTriggerMode; import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.dto.DashboardTestDTO; import io.metersphere.i18n.Translator; @@ -21,8 +25,11 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.UUID; @@ -36,6 +43,8 @@ public class APIReportService { private ApiTestReportDetailMapper apiTestReportDetailMapper; @Resource private ExtApiTestReportMapper extApiTestReportMapper; + @Resource + private ApiDataViewMapper apiDataViewMapper; public List list(QueryAPIReportRequest request) { request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders())); @@ -63,6 +72,8 @@ public class APIReportService { public void delete(DeleteAPIReportRequest request) { apiTestReportDetailMapper.deleteByPrimaryKey(request.getId()); apiTestReportMapper.deleteByPrimaryKey(request.getId()); + apiDataViewMapper.deleteByReportId(request.getId()); + } public void deleteByTestId(String testId) { @@ -89,6 +100,8 @@ public class APIReportService { // report report.setUpdateTime(System.currentTimeMillis()); if (!StringUtils.equals(report.getStatus(), APITestStatus.Debug.name())) { + //新增每一条接口记录到api_data_view表中 + creatApiDataView(new String(detail.getContent(), StandardCharsets.UTF_8), report.getId()); if (result.getError() > 0) { report.setStatus(APITestStatus.Error.name()); } else { @@ -99,6 +112,44 @@ public class APIReportService { apiTestReportMapper.updateByPrimaryKeySelective(report); } + private void creatApiDataView(String jsonString, String reportId) { + List listApiDataView = new ArrayList<>(); + JSONObject jsonObject = JSON.parseObject(jsonString, JSONObject.class); + JSONArray jsonArray = jsonObject.getJSONArray("scenarios"); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + try { + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jsonInArray = jsonArray.getJSONObject(i); + JSONArray jsonRequestResults = jsonInArray.getJSONArray("requestResults"); + for (int j = 0; j < jsonRequestResults.size(); j++) { + JSONObject jsonInResponseResult = jsonRequestResults.getJSONObject(j).getJSONObject("responseResult"); + String responseTime = jsonInResponseResult.getString("responseTime"); + String responseCode = jsonInResponseResult.getString("responseCode"); + String startTime = jsonRequestResults.getJSONObject(j).getString("startTime"); + String name = jsonRequestResults.getJSONObject(j).getString("name"); + String url = jsonRequestResults.getJSONObject(j).getString("url"); + if (StringUtils.isBlank(url)){ + //如果非http请求不入库 + continue; + } + ApiDataView apiDataView = new ApiDataView(); + apiDataView.setId(UUID.randomUUID().toString()); + apiDataView.setReportId(reportId); + apiDataView.setApiName(name); + apiDataView.setUrl(StringUtils.substringBefore(url,"?")); + apiDataView.setResponseTime(responseTime); + apiDataView.setStartTime(sdf.format(new Date(Long.parseLong(startTime)))); + apiDataView.setResponseCode(responseCode); + listApiDataView.add(apiDataView); + } + } + } catch (Exception e) { + LogUtil.error(e); + } + apiDataViewMapper.insertListApiData(listApiDataView); + + } + public String create(ApiTest test, String triggerMode) { ApiTestReport running = getRunningReport(test.getId()); if (running != null) { diff --git a/backend/src/main/java/io/metersphere/base/domain/ApiDataView.java b/backend/src/main/java/io/metersphere/base/domain/ApiDataView.java new file mode 100644 index 0000000000..8399077381 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/domain/ApiDataView.java @@ -0,0 +1,24 @@ +package io.metersphere.base.domain; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class ApiDataView implements Serializable { + private String id; + + private String reportId; + + private String url; + + private String apiName; + + private String startTime; + + private String responseCode; + + private String responseTime; + + private static final long serialVersionUID = 1L; +} diff --git a/backend/src/main/java/io/metersphere/base/mapper/ApiDataViewMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ApiDataViewMapper.java new file mode 100644 index 0000000000..48cf86c598 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/ApiDataViewMapper.java @@ -0,0 +1,23 @@ +package io.metersphere.base.mapper; + +import io.metersphere.api.dto.ApiMonitorSearch; +import io.metersphere.api.dto.ApiResponseCodeMonitor; +import io.metersphere.api.dto.ApiResponseTimeMonitor; +import io.metersphere.base.domain.ApiDataView; + +import java.util.List; + +public interface ApiDataViewMapper { + + List selectAll(); + + List selectResponseTimeByUrl(String url,String startTime,String endTime); + + List selectResponseCodeByUrl(String url,String startTime,String endTime); + + Integer insertListApiData(List list); + + Integer deleteByReportId(String reportId); + + String selectReportIdByUrlAndStartTime(String apiUrl,String startTime); +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ApiDataViewMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ApiDataViewMapper.xml new file mode 100644 index 0000000000..671a97fdb5 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/ApiDataViewMapper.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + delete from api_data_view where report_id = #{reportId,jdbcType=VARCHAR} + + + + + + + + + + + insert into api_data_view(id, report_id, api_name,url, response_code, start_time,response_time) + values + + ( + #{item.id,jdbcType=VARCHAR}, + #{item.reportId,jdbcType=VARCHAR}, + #{item.apiName,jdbcType=VARCHAR}, + #{item.url,jdbcType=VARCHAR}, + #{item.responseCode,jdbcType=VARCHAR}, + #{item.startTime,jdbcType=VARCHAR}, + #{item.responseTime,jdbcType=VARCHAR} + ) + + + \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/V47__api_data_view.sql b/backend/src/main/resources/db/migration/V47__api_data_view.sql new file mode 100644 index 0000000000..74ff59be4f --- /dev/null +++ b/backend/src/main/resources/db/migration/V47__api_data_view.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS `api_data_view` +( + id varchar(50) NOT NULL primary key, + report_id varchar(255) NOT NULL, + api_name varchar(200) NULL, + url varchar(255) NULL, + response_code varchar(100) NULL, + start_time varchar(20) NULL, + response_time varchar(20) default '0' NULL, + create_time timestamp default CURRENT_TIMESTAMP NOT NULL, + update_time timestamp default CURRENT_TIMESTAMP NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; \ No newline at end of file diff --git a/frontend/src/business/components/api/head/ApiHeaderMenus.vue b/frontend/src/business/components/api/head/ApiHeaderMenus.vue index 5e1e6f1d1f..f398905d6f 100644 --- a/frontend/src/business/components/api/head/ApiHeaderMenus.vue +++ b/frontend/src/business/components/api/head/ApiHeaderMenus.vue @@ -32,6 +32,11 @@ + + + + {{ $t('commons.monitor') }} + diff --git a/frontend/src/business/components/api/monitor/ApiMonitor.vue b/frontend/src/business/components/api/monitor/ApiMonitor.vue new file mode 100644 index 0000000000..466b1e5eea --- /dev/null +++ b/frontend/src/business/components/api/monitor/ApiMonitor.vue @@ -0,0 +1,168 @@ + + + + + diff --git a/frontend/src/business/components/api/monitor/ApiMonitorChart.vue b/frontend/src/business/components/api/monitor/ApiMonitorChart.vue new file mode 100644 index 0000000000..c7e2b1a3e8 --- /dev/null +++ b/frontend/src/business/components/api/monitor/ApiMonitorChart.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/frontend/src/business/components/api/monitor/ApiMonitorSearch.vue b/frontend/src/business/components/api/monitor/ApiMonitorSearch.vue new file mode 100644 index 0000000000..d97a9a2d33 --- /dev/null +++ b/frontend/src/business/components/api/monitor/ApiMonitorSearch.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/frontend/src/business/components/api/monitor/components/ApiErrorMonitorChart.vue b/frontend/src/business/components/api/monitor/components/ApiErrorMonitorChart.vue new file mode 100644 index 0000000000..ca7903e471 --- /dev/null +++ b/frontend/src/business/components/api/monitor/components/ApiErrorMonitorChart.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/frontend/src/business/components/api/monitor/components/ApiResponseTimeMonitorChart.vue b/frontend/src/business/components/api/monitor/components/ApiResponseTimeMonitorChart.vue new file mode 100644 index 0000000000..dccd45060e --- /dev/null +++ b/frontend/src/business/components/api/monitor/components/ApiResponseTimeMonitorChart.vue @@ -0,0 +1,64 @@ + + + + + diff --git a/frontend/src/business/components/api/monitor/components/CommonMonitorChart.vue b/frontend/src/business/components/api/monitor/components/CommonMonitorChart.vue new file mode 100644 index 0000000000..868373a31e --- /dev/null +++ b/frontend/src/business/components/api/monitor/components/CommonMonitorChart.vue @@ -0,0 +1,33 @@ + + + + + + + diff --git a/frontend/src/business/components/api/router.js b/frontend/src/business/components/api/router.js index 672d9faf7e..3528722f23 100644 --- a/frontend/src/business/components/api/router.js +++ b/frontend/src/business/components/api/router.js @@ -38,6 +38,16 @@ export default { path: "report/view/:reportId", name: "ApiReportView", component: () => import('@/business/components/api/report/ApiReportView'), - } + }, + { + path: "definition", + name: "ApiDefinition", + component: () => import('@/business/components/api/definition/ApiDefinition'), + }, + { + path: 'monitor/view', + name: 'ApiMonitor', + component: () => import('@/business/components/api/monitor/ApiMonitor'), + }, ] } diff --git a/frontend/src/common/js/ajax.js b/frontend/src/common/js/ajax.js index 3482f67ebd..9acc2d2c6c 100644 --- a/frontend/src/common/js/ajax.js +++ b/frontend/src/common/js/ajax.js @@ -70,12 +70,12 @@ export default { } } - Vue.prototype.$$get = function (url, data, success) { + Vue.prototype.$$get = function (url, data, header, success) { let result = {loading: true}; if (!success) { - return axios.get(url, {params: data}); + return axios.get(url, {params: data, headers: header}); } else { - axios.get(url, {params: data}).then(response => { + axios.get(url, {params: data, headers: header}).then(response => { then(success, response, result); }).catch(error => { exception(error, result); diff --git a/frontend/src/common/js/chart.js b/frontend/src/common/js/chart.js index f2ec0b5317..5e26e1bcc6 100644 --- a/frontend/src/common/js/chart.js +++ b/frontend/src/common/js/chart.js @@ -4,6 +4,8 @@ import 'echarts/lib/chart/bar' import 'echarts/lib/chart/pie' import 'echarts/lib/component/tooltip' import 'echarts/lib/component/title' +import 'echarts/lib/component/toolbox'; +import 'echarts/lib/component/dataZoom'; import 'zrender/lib/svg/svg' export default { diff --git a/frontend/src/common/js/format-utils.js b/frontend/src/common/js/format-utils.js index 1c1206b6fd..e207b6df90 100644 --- a/frontend/src/common/js/format-utils.js +++ b/frontend/src/common/js/format-utils.js @@ -120,6 +120,42 @@ export function formatXml(text) { return outputText.replace(/\s+$/g, '').replace(/\r/g, '\r\n'); } +/** + * @param time 时间 + * @param cFormat 格式 + * @returns {string|null} 字符串 + * @example formatTime('2018-1-29', '{y}/{m}/{d} {h}:{i}:{s}') // -> 2018/01/29 00:00:00 + */ +export function formatTime(time, cFormat) { + if (arguments.length === 0) return null; + if ((time + '').length === 10) { + time = +time * 1000; + } + let format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}', date; + if (typeof time === 'object') { + date = time; + } else { + date = new Date(time); + } + let formatObj = { + y: date.getFullYear(), + m: date.getMonth() + 1, + d: date.getDate(), + h: date.getHours(), + i: date.getMinutes(), + s: date.getSeconds(), + a: date.getDay() + }; + return format.replace(/{([ymdhisa])+}/g, (result, key) => { + let value = formatObj[key]; + if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]; + if (result.length > 0 && value < 10) { + value = '0' + value; + } + return value || 0; + }); +} + function getPrefix(prefixIndex) { var span = ' '; var output = []; diff --git a/frontend/src/i18n/en-US.js b/frontend/src/i18n/en-US.js index bfc2f4a616..7e69aaaffc 100644 --- a/frontend/src/i18n/en-US.js +++ b/frontend/src/i18n/en-US.js @@ -162,7 +162,8 @@ export default { between: "Between", current_user: "Current user" } - } + }, + monitor:"monitor" }, license: { title: 'Authorization management', @@ -707,6 +708,16 @@ export default { running: "The test is reporting", not_exist: "Test report does not exist", }, + api_monitor: { + to:"to", + start_time:"Start Time", + end_time:"End Time", + today:"Today", + this_week:"This Week", + this_mouth:"This Mouth", + please_search:"Please Search", + date:"Date" + }, test_track: { test_track: "Track", confirm: "Confirm", diff --git a/frontend/src/i18n/zh-CN.js b/frontend/src/i18n/zh-CN.js index 6974ad127a..45403e5574 100644 --- a/frontend/src/i18n/zh-CN.js +++ b/frontend/src/i18n/zh-CN.js @@ -162,7 +162,8 @@ export default { between: "之间", current_user: "是当前用户" } - } + }, + monitor: "监控" }, license: { title: '授权管理', @@ -709,6 +710,16 @@ export default { running: "测试报告导出中", not_exist: "测试报告不存在", }, + api_monitor: { + to:"至", + start_time:"开始日期", + end_time:"结束日期", + today:"今日", + this_week:"本周", + this_mouth:"本月", + please_search:"请搜索", + date:"日期" + }, test_track: { test_track: "测试跟踪", confirm: "确 定", diff --git a/frontend/src/i18n/zh-TW.js b/frontend/src/i18n/zh-TW.js index 62a1a3e3c7..9af605db4a 100644 --- a/frontend/src/i18n/zh-TW.js +++ b/frontend/src/i18n/zh-TW.js @@ -162,7 +162,8 @@ export default { between: "之間", current_user: "是當前用戶" } - } + }, + monitor:"監控" }, license: { title: '授權管理', @@ -710,6 +711,16 @@ export default { running: "測試報告導出中", not_exist: "測試報告不存在", }, + api_monitor: { + to:"到", + start_time:"開始時間", + end_time:"結束時間", + today:"今天", + this_week:"本週", + this_mouth:"本月", + please_search:"請搜索", + date:"日期" + }, test_track: { test_track: "測試跟蹤", confirm: "確 定", From 0acc2a915db2ac1ef3c5c080c38e17ae9186f95d Mon Sep 17 00:00:00 2001 From: BugKing Date: Mon, 30 Nov 2020 19:07:44 +0800 Subject: [PATCH 4/9] =?UTF-8?q?refactor:=20=E8=A7=A3=E5=86=B3=E5=90=88?= =?UTF-8?q?=E5=B9=B6=E5=90=8E=E7=9A=84=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/business/components/api/router.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/frontend/src/business/components/api/router.js b/frontend/src/business/components/api/router.js index 3528722f23..dbb73ae0c0 100644 --- a/frontend/src/business/components/api/router.js +++ b/frontend/src/business/components/api/router.js @@ -39,11 +39,6 @@ export default { name: "ApiReportView", component: () => import('@/business/components/api/report/ApiReportView'), }, - { - path: "definition", - name: "ApiDefinition", - component: () => import('@/business/components/api/definition/ApiDefinition'), - }, { path: 'monitor/view', name: 'ApiMonitor', From 6a4f78d2feea85162f35640c832bae72c678b0ae Mon Sep 17 00:00:00 2001 From: BugKing Date: Mon, 30 Nov 2020 20:44:58 +0800 Subject: [PATCH 5/9] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=9B=91=E6=8E=A7=E5=93=8D=E5=BA=94=E7=A0=81?= =?UTF-8?q?=E5=9B=BE=E8=A1=A8=E4=B8=8D=E6=98=BE=E7=A4=BA=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/business/components/api/monitor/ApiMonitor.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/business/components/api/monitor/ApiMonitor.vue b/frontend/src/business/components/api/monitor/ApiMonitor.vue index 466b1e5eea..e5dab060db 100644 --- a/frontend/src/business/components/api/monitor/ApiMonitor.vue +++ b/frontend/src/business/components/api/monitor/ApiMonitor.vue @@ -95,7 +95,7 @@ export default { {'apiUrl': this.apiUrl}, response => { Object.values(response.data).forEach(value => { this.rspCodexAxis.push(value.startTime); - this.rspCodeData.push(value.responseTime); + this.rspCodeData.push(value.responseCode); }); }); }, From 4a26b3baf66022f06f9bd311630fdf481dabe95e Mon Sep 17 00:00:00 2001 From: "Captain.B" Date: Tue, 1 Dec 2020 10:14:06 +0800 Subject: [PATCH 6/9] =?UTF-8?q?fix(=E6=80=A7=E8=83=BD=E6=B5=8B=E8=AF=95):?= =?UTF-8?q?=20=E5=8E=BB=E6=8E=89input=E4=B8=AD=E7=9A=84placeholder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #838 --- .../test/components/PerformancePressureConfig.vue | 5 ----- 1 file changed, 5 deletions(-) diff --git a/frontend/src/business/components/performance/test/components/PerformancePressureConfig.vue b/frontend/src/business/components/performance/test/components/PerformancePressureConfig.vue index 7d51c4f387..ac335bdcb3 100644 --- a/frontend/src/business/components/performance/test/components/PerformancePressureConfig.vue +++ b/frontend/src/business/components/performance/test/components/PerformancePressureConfig.vue @@ -27,7 +27,6 @@ Date: Tue, 1 Dec 2020 10:29:57 +0800 Subject: [PATCH 7/9] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=85=B3=E9=97=AD?= =?UTF-8?q?rpsLimit=E6=97=B6=EF=BC=8C=E4=B8=8D=E8=BE=93=E5=85=A5rpsLimit?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E4=BF=9D=E5=AD=98=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #839 --- .../test/components/PerformancePressureConfig.vue | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/src/business/components/performance/test/components/PerformancePressureConfig.vue b/frontend/src/business/components/performance/test/components/PerformancePressureConfig.vue index ac335bdcb3..5d98032542 100644 --- a/frontend/src/business/components/performance/test/components/PerformancePressureConfig.vue +++ b/frontend/src/business/components/performance/test/components/PerformancePressureConfig.vue @@ -460,7 +460,13 @@ export default { for (let i = 0; i < this.threadGroups.length; i++) { if (!this.threadGroups[i].threadNumber || !this.threadGroups[i].duration - || !this.threadGroups[i].rampUpTime || !this.threadGroups[i].step || !this.threadGroups[i].rpsLimit) { + || !this.threadGroups[i].rampUpTime || !this.threadGroups[i].step) { + this.$warning(this.$t('load_test.pressure_config_params_is_empty')); + this.$emit('changeActive', '1'); + return false; + } + + if (this.threadGroups[i].rpsLimitEnable && !this.threadGroups[i].rpsLimit) { this.$warning(this.$t('load_test.pressure_config_params_is_empty')); this.$emit('changeActive', '1'); return false; From 97448b39d5571df7aa36cdeb66889aaf2427fedf Mon Sep 17 00:00:00 2001 From: BugKing Date: Fri, 4 Dec 2020 10:01:14 +0800 Subject: [PATCH 8/9] =?UTF-8?q?build:=20=E5=A2=9E=E5=8A=A0=20action?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build-push.yml | 64 ++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 .github/workflows/build-push.yml diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml new file mode 100644 index 0000000000..a87efc78c3 --- /dev/null +++ b/.github/workflows/build-push.yml @@ -0,0 +1,64 @@ +name: Build Docker Image and Push + +on: + push: + branches: + - master + - v1* + pull_request: + branches: + - master + - v1* + + workflow_dispatch: + +jobs: + build_push: + runs-on: ubuntu-latest + name: Build Docker Image and Push + steps: + - uses: actions/checkout@v2 + with: + submodules: true + token: ${{ secrets.ACCESS_TOKEN }} + + - name: Inject slug/short variables + uses: rlespinasse/github-slug-action@v3.x + - name: Cache node modules + uses: actions/cache@v2 + env: + cache-name: cache-node-modules + with: + path: ~/.npm + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: Cache local Maven repository + uses: actions/cache@v2 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + server-id: github # Value of the distributionManagement/repository/id field of the pom.xml + settings-path: ${{ github.workspace }} # location for the settings.xml file + + - name: Build with Maven + run: mvn -B package --file pom.xml + + - name: Push to Docker Hub + uses: docker/build-push-action@v1 + with: + username: metersphere + password: ${{ secrets.DOCKER_HUB_TOKEN }} + repository: metersphere/metersphere + tag_with_ref: true + build_args: MS_VERSION=${{ env.GITHUB_REF_SLUG }}-${{ env.GITHUB_SHA_SHORT }} From 2c316439bc2cf481ec07c6515083113918d48fd0 Mon Sep 17 00:00:00 2001 From: BugKing Date: Thu, 3 Dec 2020 18:25:25 +0800 Subject: [PATCH 9/9] =?UTF-8?q?build:=20=E4=BF=AE=E6=94=B9=20Dockerfile=20?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E9=95=9C=E5=83=8F=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 8e0a6e24fa..5dc3c7e4d7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM registry.fit2cloud.com/metersphere/fabric8-java-alpine-openjdk8-jre +FROM metersphere/fabric8-java-alpine-openjdk8-jre MAINTAINER FIT2CLOUD