This is an automated email from the ASF dual-hosted git repository.
peacewong pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/linkis.git
The following commit(s) were added to refs/heads/master by this push:
new c8f9537c99 [FEATURE] add kanban in linkisweb (#5089)
c8f9537c99 is described below
commit c8f9537c990bc19e0ef3e5e320197c6d5c66bd41
Author: LiuGuoHua <[email protected]>
AuthorDate: Wed Mar 13 14:29:48 2024 +0800
[FEATURE] add kanban in linkisweb (#5089)
* Add new features to the Kanban view
* Add new features to the Kanban view
* Add query parameters to the interface
* Add code to the front-end section of the Kanban view
* 1. 增加筛选项目
2. 拆分mysql/pgsql
* 1. 修复resultMap重复的bug
2. 去除无用字段
* 1. 优化mapper sql
* 1. 调整显示格式
* 1. formatted code
* 1. fix error name
* 1. formatted code
* fotmatted code
* matted code
---
.../linkis/jobhistory/dao/JobHistoryMapper.java | 22 +
.../linkis/jobhistory/dao/JobStatisticsMapper.java | 63 ++
.../linkis/jobhistory/entity/JobStatistics.java | 76 ++
.../jobhistory/restful/api/QueryRestfulApi.java | 89 +++
.../restful/api/StatisticsRestfulApi.java | 195 +++++
.../mapper/common/JobStatisticsMapper.xml | 52 ++
.../resources/mapper/mysql/JobHistoryMapper.xml | 70 +-
.../resources/mapper/mysql/JobStatisticsMapper.xml | 86 +++
.../mapper/postgresql/JobHistoryMapper.xml | 71 +-
.../mapper/postgresql/JobStatisticsMapper.xml | 86 +++
.../jobhistory/service/JobHistoryQueryService.java | 8 +-
.../service/JobStatisticsQueryService.java | 30 +
.../service/impl/JobHistoryQueryServiceImpl.scala | 40 ++
.../impl/JobStatisticsQueryServiceImpl.scala | 108 +++
linkis-web/package.json | 3 +-
linkis-web/src/apps/linkis/i18n/common/en.json | 8 +-
linkis-web/src/apps/linkis/i18n/common/zh.json | 6 +-
.../linkis/module/statisticsDashboard/index.js | 25 +
.../linkis/module/statisticsDashboard/index.scss | 157 ++++
.../linkis/module/statisticsDashboard/index.vue | 786 +++++++++++++++++++++
.../statisticsDashboard/statisticsDashboard.vue | 441 ++++++++++++
linkis-web/src/apps/linkis/router.js | 20 +
linkis-web/src/apps/linkis/view/linkis/index.vue | 7 +
23 files changed, 2410 insertions(+), 39 deletions(-)
diff --git
a/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/dao/JobHistoryMapper.java
b/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/dao/JobHistoryMapper.java
index 300d00b989..c01720a5f3 100644
---
a/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/dao/JobHistoryMapper.java
+++
b/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/dao/JobHistoryMapper.java
@@ -130,4 +130,26 @@ public interface JobHistoryMapper {
@Param("statusList") List<String> statusList,
@Param("startTimestamp") Long startTimestamp,
@Param("limit") Integer limit);
+
+ List<JobHistory> taskDurationTopN(
+ @Param("startDate") Date startDate,
+ @Param("endDate") Date endDate,
+ @Param("umUser") String username,
+ @Param("engineType") String engineType);
+
+ List<JobHistory> taskDurationTopNWithUserCreator(
+ @Param("umUser") String username,
+ @Param("userCreatorKey") String userCreatorKey,
+ @Param("userCreatorValue") String userCreator,
+ @Param("startDate") Date startDate,
+ @Param("endDate") Date endDate,
+ @Param("engineType") String engineType);
+
+ List<JobHistory> taskDurationTopNWithCreatorOnly(
+ @Param("umUser") String username,
+ @Param("userCreatorKey") String userCreatorKey,
+ @Param("creator") String userCreator,
+ @Param("startDate") Date startDate,
+ @Param("endDate") Date endDate,
+ @Param("engineType") String engineType);
}
diff --git
a/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/dao/JobStatisticsMapper.java
b/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/dao/JobStatisticsMapper.java
new file mode 100644
index 0000000000..9c0ee86d9e
--- /dev/null
+++
b/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/dao/JobStatisticsMapper.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.linkis.jobhistory.dao;
+
+import org.apache.linkis.jobhistory.entity.JobStatistics;
+
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+
+public interface JobStatisticsMapper {
+
+ JobStatistics taskExecutionStatistics(
+ @Param("umUser") String username,
+ @Param("startDate") Date startDate,
+ @Param("endDate") Date endDate,
+ @Param("engineType") String engineType);
+
+ JobStatistics taskExecutionStatisticsWithUserCreator(
+ @Param("umUser") String username,
+ @Param("userCreatorKey") String userCreatorKey,
+ @Param("userCreatorValue") String userCreator,
+ @Param("startDate") Date startDate,
+ @Param("endDate") Date endDate,
+ @Param("engineType") String engineType);
+
+ JobStatistics taskExecutionStatisticsWithCreatorOnly(
+ @Param("umUser") String username,
+ @Param("userCreatorKey") String userCreatorKey,
+ @Param("creator") String userCreator,
+ @Param("startDate") Date startDate,
+ @Param("endDate") Date endDate,
+ @Param("engineType") String engineType);
+
+ JobStatistics engineExecutionStatisticsWithUserCreator(
+ @Param("umUser") String username,
+ @Param("userCreatorValue") String userCreator,
+ @Param("startDate") Date startDate,
+ @Param("endDate") Date endDate,
+ @Param("engineType") String engineType);
+
+ JobStatistics engineExecutionStatistics(
+ @Param("umUser") String username,
+ @Param("creator") String userCreator,
+ @Param("startDate") Date startDate,
+ @Param("endDate") Date endDate,
+ @Param("engineType") String engineType);
+}
diff --git
a/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/entity/JobStatistics.java
b/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/entity/JobStatistics.java
new file mode 100644
index 0000000000..23621708f5
--- /dev/null
+++
b/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/entity/JobStatistics.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.linkis.jobhistory.entity;
+
+public class JobStatistics {
+
+ private Long id;
+
+ private Integer sumCount;
+
+ private Integer succeedCount;
+
+ private Integer failedCount;
+
+ private Integer cancelledCount;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Integer getSumCount() {
+ return sumCount;
+ }
+
+ public void setSumCount(Integer sumCount) {
+ this.sumCount = sumCount;
+ }
+
+ public Integer getSucceedCount() {
+ return succeedCount;
+ }
+
+ public void setSucceedCount(Integer succeedCount) {
+ this.succeedCount = succeedCount;
+ }
+
+ public Integer getFailedCount() {
+ return failedCount;
+ }
+
+ public void setFailedCount(Integer failedCount) {
+ this.failedCount = failedCount;
+ }
+
+ public Integer getCancelledCount() {
+ return cancelledCount;
+ }
+
+ public void setCancelledCount(Integer cancelledCount) {
+ this.cancelledCount = cancelledCount;
+ }
+
+ @Override
+ public String toString() {
+ return "JobHistory{" + "id=" + id + '}';
+ }
+}
diff --git
a/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/restful/api/QueryRestfulApi.java
b/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/restful/api/QueryRestfulApi.java
index a18da3a042..0ae72b84b3 100644
---
a/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/restful/api/QueryRestfulApi.java
+++
b/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/restful/api/QueryRestfulApi.java
@@ -412,4 +412,93 @@ public class QueryRestfulApi {
return Message.ok().data(JobRequestConstants.TOTAL_PAGE(), total);
}
+
+ /** Method list should not contain subjob, which may cause performance
problems. */
+ @ApiOperation(value = "listDurationTop", notes = "listDurationTop", response
= Message.class)
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "startDate", dataType = "long", example =
"1658937600001"),
+ @ApiImplicitParam(name = "endDate", dataType = "long", example =
"1658937600000"),
+ @ApiImplicitParam(name = "executeApplicationName", dataType = "String"),
+ @ApiImplicitParam(name = "creator", required = false, dataType = "String",
value = "creator"),
+ @ApiImplicitParam(
+ name = "proxyUser",
+ required = false,
+ dataType = "String",
+ value = "proxyUser"),
+ @ApiImplicitParam(name = "pageNow", required = false, dataType =
"Integer", value = "page now"),
+ @ApiImplicitParam(name = "pageSize", dataType = "Integer"),
+ })
+ @RequestMapping(path = "/listDurationTop", method = RequestMethod.GET)
+ public Message listDurationTop(
+ HttpServletRequest req,
+ @RequestParam(value = "startDate", required = false) Long startDate,
+ @RequestParam(value = "endDate", required = false) Long endDate,
+ @RequestParam(value = "executeApplicationName", required = false)
+ String executeApplicationName,
+ @RequestParam(value = "creator", required = false) String creator,
+ @RequestParam(value = "proxyUser", required = false) String proxyUser,
+ @RequestParam(value = "pageNow", required = false) Integer pageNow,
+ @RequestParam(value = "pageSize", required = false) Integer pageSize)
+ throws QueryException {
+ if (StringUtils.isEmpty(pageNow)) {
+ pageNow = 1;
+ }
+ if (StringUtils.isEmpty(pageSize)) {
+ pageSize = 20;
+ }
+ if (StringUtils.isEmpty(proxyUser)) {
+ proxyUser = null;
+ } else {
+ if (!QueryUtils.checkNameValid(proxyUser)) {
+ return Message.error("Invalid proxyUser : " + proxyUser);
+ }
+ }
+ if (StringUtils.isEmpty(creator)) {
+ creator = null;
+ } else {
+ if (!QueryUtils.checkNameValid(creator)) {
+ return Message.error("Invalid creator : " + creator);
+ }
+ }
+ if (!StringUtils.isEmpty(executeApplicationName)) {
+ if (!QueryUtils.checkNameValid(executeApplicationName)) {
+ return Message.error("Invalid applicationName : " +
executeApplicationName);
+ }
+ } else {
+ executeApplicationName = null;
+ }
+
+ if (endDate == null) {
+ endDate = System.currentTimeMillis();
+ }
+ if (startDate == null) {
+ startDate = 0L;
+ }
+
+ Date sDate = new Date(startDate);
+ Date eDate = new Date(endDate);
+ if (sDate.getTime() == eDate.getTime()) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(endDate);
+ calendar.add(Calendar.DAY_OF_MONTH, 1);
+ eDate = new Date(calendar.getTime().getTime()); // todo check
+ }
+ List<JobHistory> queryTasks = null;
+ PageHelper.startPage(pageNow, pageSize);
+ try {
+ queryTasks =
+ jobHistoryQueryService.taskDurationTopN(
+ sDate, eDate, proxyUser, creator, executeApplicationName);
+ } finally {
+ PageHelper.clearPage();
+ }
+
+ List<QueryTaskVO> vos = new ArrayList<>();
+ for (JobHistory jobHistory : queryTasks) {
+ QueryUtils.exchangeExecutionCode(jobHistory);
+ QueryTaskVO taskVO = TaskConversions.jobHistory2TaskVO(jobHistory, null);
+ vos.add(taskVO);
+ }
+ return Message.ok().data(TaskConstant.TASKS, vos);
+ }
}
diff --git
a/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/restful/api/StatisticsRestfulApi.java
b/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/restful/api/StatisticsRestfulApi.java
new file mode 100644
index 0000000000..23a12c2b94
--- /dev/null
+++
b/linkis-public-enhancements/linkis-jobhistory/src/main/java/org/apache/linkis/jobhistory/restful/api/StatisticsRestfulApi.java
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.linkis.jobhistory.restful.api;
+
+import org.apache.linkis.governance.common.entity.job.QueryException;
+import org.apache.linkis.jobhistory.entity.JobStatistics;
+import org.apache.linkis.jobhistory.service.JobStatisticsQueryService;
+import org.apache.linkis.jobhistory.util.QueryUtils;
+import org.apache.linkis.server.Message;
+
+import org.apache.commons.lang3.time.DateUtils;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.Date;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Api(tags = "jobstatistics api")
+@RestController
+@RequestMapping(path = "/jobhistory/jobstatistics")
+public class StatisticsRestfulApi {
+
+ private Logger log = LoggerFactory.getLogger(this.getClass());
+
+ @Autowired private JobStatisticsQueryService jobStatisticsQueryService;
+
+ @ApiOperation(value = "taskCount", notes = "taskCount", response =
Message.class)
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "startDate", dataType = "long"),
+ @ApiImplicitParam(name = "endDate", required = false, dataType = "long",
value = "end date"),
+ @ApiImplicitParam(name = "executeApplicationName", dataType = "String"),
+ @ApiImplicitParam(name = "creator", required = false, dataType = "String",
value = "creator"),
+ @ApiImplicitParam(
+ name = "proxyUser",
+ required = false,
+ dataType = "String",
+ value = "proxyUser"),
+ })
+ @RequestMapping(path = "/taskCount", method = RequestMethod.GET)
+ public Message taskCount(
+ HttpServletRequest req,
+ @RequestParam(value = "startDate", required = false) Long startDate,
+ @RequestParam(value = "endDate", required = false) Long endDate,
+ @RequestParam(value = "executeApplicationName", required = false)
+ String executeApplicationName,
+ @RequestParam(value = "creator", required = false) String creator,
+ @RequestParam(value = "proxyUser", required = false) String proxyUser)
+ throws IOException, QueryException {
+ if (endDate == null) {
+ endDate = System.currentTimeMillis();
+ }
+ if (startDate == null) {
+ startDate = 0L;
+ }
+ Date sDate = new Date(startDate);
+ Date eDate = new Date(endDate);
+ if (startDate == 0L) {
+ sDate = DateUtils.addDays(eDate, -1);
+ }
+ if (sDate.getTime() == eDate.getTime()) {
+ Calendar instance = Calendar.getInstance();
+ instance.setTimeInMillis(endDate);
+ instance.add(Calendar.DAY_OF_MONTH, 1);
+ eDate = new Date(instance.getTime().getTime());
+ }
+ if (StringUtils.isEmpty(proxyUser)) {
+ proxyUser = null;
+ } else {
+ if (!QueryUtils.checkNameValid(proxyUser)) {
+ return Message.error("Invalid proxyUser : " + proxyUser);
+ }
+ }
+ if (StringUtils.isEmpty(creator)) {
+ creator = null;
+ } else {
+ if (!QueryUtils.checkNameValid(creator)) {
+ return Message.error("Invalid creator : " + creator);
+ }
+ }
+ if (!StringUtils.isEmpty(executeApplicationName)) {
+ if (!QueryUtils.checkNameValid(executeApplicationName)) {
+ return Message.error("Invalid applicationName : " +
executeApplicationName);
+ }
+ } else {
+ executeApplicationName = null;
+ }
+ JobStatistics jobStatistics =
+ jobStatisticsQueryService.taskExecutionStatistics(
+ sDate, eDate, proxyUser, creator, executeApplicationName);
+
+ return Message.ok()
+ .data("sumCount", jobStatistics.getSumCount())
+ .data("succeedCount", jobStatistics.getSucceedCount())
+ .data("failedCount", jobStatistics.getFailedCount())
+ .data("cancelledCount", jobStatistics.getCancelledCount());
+ }
+
+ @ApiOperation(value = "engineCount", notes = "engineCount", response =
Message.class)
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "startDate", dataType = "long"),
+ @ApiImplicitParam(name = "endDate", required = false, dataType = "long",
value = "end date"),
+ @ApiImplicitParam(name = "executeApplicationName", dataType = "String"),
+ @ApiImplicitParam(name = "creator", required = false, dataType = "String",
value = "creator"),
+ @ApiImplicitParam(
+ name = "proxyUser",
+ required = false,
+ dataType = "String",
+ value = "proxyUser"),
+ })
+ @RequestMapping(path = "/engineCount", method = RequestMethod.GET)
+ public Message engineCount(
+ HttpServletRequest req,
+ @RequestParam(value = "startDate", required = false) Long startDate,
+ @RequestParam(value = "endDate", required = false) Long endDate,
+ @RequestParam(value = "executeApplicationName", required = false)
+ String executeApplicationName,
+ @RequestParam(value = "creator", required = false) String creator,
+ @RequestParam(value = "proxyUser", required = false) String proxyUser)
+ throws IOException, QueryException {
+ if (endDate == null) {
+ endDate = System.currentTimeMillis();
+ }
+ if (startDate == null) {
+ startDate = 0L;
+ }
+ Date sDate = new Date(startDate);
+ Date eDate = new Date(endDate);
+ if (startDate == 0L) {
+ sDate = DateUtils.addDays(eDate, -1);
+ }
+ if (sDate.getTime() == eDate.getTime()) {
+ Calendar instance = Calendar.getInstance();
+ instance.setTimeInMillis(endDate);
+ instance.add(Calendar.DAY_OF_MONTH, 1);
+ eDate = new Date(instance.getTime().getTime());
+ }
+ if (StringUtils.isEmpty(proxyUser)) {
+ proxyUser = null;
+ } else {
+ if (!QueryUtils.checkNameValid(proxyUser)) {
+ return Message.error("Invalid proxyUser : " + proxyUser);
+ }
+ }
+ if (StringUtils.isEmpty(creator)) {
+ creator = null;
+ } else {
+ if (!QueryUtils.checkNameValid(creator)) {
+ return Message.error("Invalid creator : " + creator);
+ }
+ }
+ if (!StringUtils.isEmpty(executeApplicationName)) {
+ if (!QueryUtils.checkNameValid(executeApplicationName)) {
+ return Message.error("Invalid applicationName : " +
executeApplicationName);
+ }
+ } else {
+ executeApplicationName = null;
+ }
+ JobStatistics jobStatistics =
+ jobStatisticsQueryService.engineExecutionStatistics(
+ sDate, eDate, proxyUser, creator, executeApplicationName);
+
+ return Message.ok()
+ .data("countEngine", jobStatistics.getSumCount())
+ .data("countEngineSucceed", jobStatistics.getSucceedCount())
+ .data("countEngineFailed", jobStatistics.getFailedCount())
+ .data("countEngineShutting", jobStatistics.getCancelledCount());
+ }
+}
diff --git
a/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/common/JobStatisticsMapper.xml
b/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/common/JobStatisticsMapper.xml
new file mode 100644
index 0000000000..809f82e3fc
--- /dev/null
+++
b/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/common/JobStatisticsMapper.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+
+<mapper namespace="org.apache.linkis.jobhistory.dao.JobStatisticsMapper">
+
+ <resultMap id="jobStatisticsMap"
type="org.apache.linkis.jobhistory.entity.JobStatistics" autoMapping="false" >
+ <id property="id" column="id" />
+ <result property = "sumCount" column = "sumcount" />
+ <result property = "succeedCount" column = "succeedcount" />
+ <result property = "failedCount" column = "failedcount" />
+ <result property = "cancelledCount" column = "cancelledcount" />
+ </resultMap>
+
+
+ <select id="taskExecutionStatistics" useCache="true"
resultMap="jobStatisticsMap" >
+ SELECT COUNT(1) sumcount, COUNT(case WHEN status ='Succeed' then 1
END) succeedcount,
+ COUNT(case WHEN status ='Failed' then 1 END) failedcount,
+ COUNT(case WHEN status ='Cancelled' then 1 END) cancelledcount
+ FROM linkis_ps_job_history_group_history
+ <where>
+ <if test="umUser != null">
+ and submit_user = #{umUser}
+ </if>
+ <if test="engineType != null">
+ and engine_type = #{engineType}
+ </if>
+ <if test="startDate != null">
+ and created_time >= #{startDate} AND created_time
<![CDATA[<=]]> #{endDate}
+ </if>
+ </where>
+ </select>
+
+
+</mapper>
diff --git
a/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/mysql/JobHistoryMapper.xml
b/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/mysql/JobHistoryMapper.xml
index a5b769f2d3..6644f6b54b 100644
---
a/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/mysql/JobHistoryMapper.xml
+++
b/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/mysql/JobHistoryMapper.xml
@@ -64,7 +64,7 @@
</insert>
- <select id="selectJobHistory" useCache="false" resultMap="jobHistoryMap"
parameterType="org.apache.linkis.jobhistory.entity.JobHistory">
+ <select id="selectJobHistory" useCache="false" resultMap="jobHistoryMap"
parameterType="org.apache.linkis.jobhistory.entity.JobHistory">
SELECT * FROM linkis_ps_job_history_group_history
<where>
<if test="id != null">id = #{id}</if>
@@ -170,11 +170,11 @@
<select id="selectJobHistoryStatusForUpdate" flushCache="true"
resultType="java.lang.String">
SELECT
- bdt.status
+ bdt.status
FROM
- linkis_ps_job_history_group_history bdt
+ linkis_ps_job_history_group_history bdt
WHERE
- id = #{jobId} FOR UPDATE
+ id = #{jobId} FOR UPDATE
</select>
<select id="countUndoneTaskNoCreator" useCache="true"
resultType="java.lang.Integer" >
@@ -232,18 +232,18 @@
<select id="selectFailoverJobHistory" resultMap="jobHistoryMap" >
SELECT a.* FROM linkis_ps_job_history_group_history a
WHERE (
- a.instances = ''
- OR a.instances IS NULL
- OR a.instances NOT IN <foreach collection="instancesMap.keys"
open="(" separator="," close=")" item="key">#{key}</foreach>
- OR EXISTS (
- SELECT 1 FROM
- (
- <foreach collection="instancesMap.entrySet()"
separator="union all" index="key" item="val">
- SELECT #{key} AS instances, #{val} AS registryTime
- </foreach>
- ) b
- WHERE a.instances = b.instances AND a.created_time
<![CDATA[<]]> FROM_UNIXTIME(b.registryTime/1000)
- )
+ a.instances = ''
+ OR a.instances IS NULL
+ OR a.instances NOT IN <foreach collection="instancesMap.keys" open="("
separator="," close=")" item="key">#{key}</foreach>
+ OR EXISTS (
+ SELECT 1 FROM
+ (
+ <foreach collection="instancesMap.entrySet()" separator="union all"
index="key" item="val">
+ SELECT #{key} AS instances, #{val} AS registryTime
+ </foreach>
+ ) b
+ WHERE a.instances = b.instances AND a.created_time <![CDATA[<]]>
FROM_UNIXTIME(b.registryTime/1000)
+ )
)
AND
status IN <foreach collection="statusList" open="(" separator=","
close=")" item="status">#{status}</foreach>
@@ -252,4 +252,42 @@
</select>
+ <select id="taskDurationTopN" useCache="true" resultMap="jobHistoryMap" >
+ /*slave*/ SELECT * FROM linkis_ps_job_history_group_history
+ <where>
+ <if test="umUser != null">and submit_user = #{umUser}</if>
+ <if test="engineType != null">and engine_type = #{engineType}</if>
+ <if test="startDate != null">and created_time >= #{startDate} AND
created_time <![CDATA[<=]]> #{endDate}</if>
+ </where>
+ ORDER BY FROM_UNIXTIME(TIMEDIFF(cast(updated_time as datetime),
cast(created_time as datetime))) desc
+ </select>
+
+ <select id="taskDurationTopNWithCreatorOnly" useCache="true"
resultMap="jobHistoryMap" >
+ /*slave*/ SELECT * FROM linkis_ps_job_history_group_history
+ <where>
+ <if test="umUser != null">and submit_user = #{umUser}</if>
+ <if test="engineType != null">and engine_type = #{engineType}</if>
+ <if test="startDate != null">and created_time >= #{startDate} AND
created_time <![CDATA[<=]]>#{endDate}
+ </if>
+ <if test="userCreatorKey != null and creator != null">
+ and labels like CONCAT('%"', #{userCreatorKey}, '":"%-',
#{creator}, '%')
+ </if>
+ </where>
+ ORDER BY FROM_UNIXTIME(TIMEDIFF(cast(updated_time as datetime),
cast(created_time as datetime))) desc
+ </select>
+
+ <select id="taskDurationTopNWithUserCreator" useCache="true"
resultMap="jobHistoryMap" >
+ /*slave*/ SELECT * FROM linkis_ps_job_history_group_history
+ <where>
+ <if test="umUser != null">and submit_user = #{umUser}</if>
+ <if test="engineType != null">and engine_type = #{engineType}</if>
+ <if test="startDate != null">and created_time >= #{startDate} AND
created_time <![CDATA[<=]]>#{endDate}
+ </if>
+ <if test="userCreatorKey != null and userCreatorValue != null">
+ and LOCATE(CONCAT('"', #{userCreatorKey}, '":"',
#{userCreatorValue}), labels) > 0
+ </if>
+ </where>
+ ORDER BY FROM_UNIXTIME(TIMEDIFF(cast(updated_time as datetime),
cast(created_time as datetime))) desc
+ </select>
+
</mapper>
diff --git
a/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/mysql/JobStatisticsMapper.xml
b/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/mysql/JobStatisticsMapper.xml
new file mode 100644
index 0000000000..d05728faac
--- /dev/null
+++
b/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/mysql/JobStatisticsMapper.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+
+<mapper namespace="org.apache.linkis.jobhistory.dao.JobStatisticsMapper">
+
+ <select id="taskExecutionStatisticsWithCreatorOnly" useCache="true"
resultMap="jobStatisticsMap">
+ SELECT COUNT(1) sumcount, COUNT(case WHEN status ='Succeed' then 1
END) succeedcount,
+ COUNT(case WHEN status ='Failed' then 1 END) failedcount,
+ COUNT(case WHEN status ='Cancelled' then 1 END) cancelledcount
+ FROM linkis_ps_job_history_group_history
+ <where>
+ <if test="umUser != null">and submit_user = #{umUser}</if>
+ <if test="engineType != null">and engine_type = #{engineType}</if>
+ <if test="startDate != null">and created_time >= #{startDate} AND
created_time <![CDATA[<=]]> #{endDate}</if>
+ <if test="userCreatorKey != null and creator != null">
+ and labels like CONCAT('%"', #{userCreatorKey}, '":"%-',
#{creator}, '%')
+ </if>
+ </where>
+ </select>
+
+ <select id="taskExecutionStatisticsWithUserCreator" useCache="true"
resultMap="jobStatisticsMap">
+ SELECT COUNT(1) sumcount, COUNT(case WHEN status ='Succeed' then 1
END) succeedcount,
+ COUNT(case WHEN status ='Failed' then 1 END) failedcount,
+ COUNT(case WHEN status ='Cancelled' then 1 END) cancelledcount
+ FROM linkis_ps_job_history_group_history
+ <where>
+ <if test="umUser != null">and submit_user = #{umUser}</if>
+ <if test="engineType != null">and engine_type = #{engineType}</if>
+ <if test="startDate != null">and created_time >= #{startDate} AND
created_time <![CDATA[<=]]>#{endDate}
+ </if>
+ <if test="userCreatorKey != null and userCreatorValue != null">
+ and LOCATE(CONCAT('"', #{userCreatorKey}, '":"',
#{userCreatorValue}), labels) > 0
+ </if>
+ </where>
+ </select>
+
+ <select id="engineExecutionStatistics" useCache="true"
resultMap="jobStatisticsMap">
+ SELECT COUNT(1) sumcount, COUNT(case WHEN status ='Success' then 1
END) succeedcount,
+ COUNT(case WHEN status ='Failed' then 1 END) failedcount,
+ COUNT(case WHEN status ='ShuttingDown' then 1 END) cancelledcount FROM
+ linkis_cg_ec_resource_info_record
+ <where>
+ <if test="umUser != null">and create_user = #{umUser}</if>
+ <if test="engineType != null">and label_value like CONCAT('%',
#{engineType},'%')</if>
+ <if test="startDate != null">and create_time >= #{startDate} AND
create_time <![CDATA[<=]]> #{endDate}</if>
+ <if test="creator != null">
+ and label_value like CONCAT('%-', #{creator}, '%')
+ </if>
+ </where>
+ </select>
+
+ <select id="engineExecutionStatisticsWithUserCreator" useCache="true"
resultMap="jobStatisticsMap">
+ SELECT COUNT(1) sumcount, COUNT(case WHEN status ='Success' then 1
END) succeedcount,
+ COUNT(case WHEN status ='Failed' then 1 END) failedcount,
+ COUNT(case WHEN status ='ShuttingDown' then 1 END) cancelledcount FROM
+ linkis_cg_ec_resource_info_record
+ <where>
+ <if test="umUser != null">and create_user = #{umUser}</if>
+ <if test="engineType != null">and label_value like CONCAT('%',
#{engineType},'%')</if>
+ <if test="startDate != null">and create_time >= #{startDate} AND
create_time <![CDATA[<=]]> #{endDate}</if>
+ <if test="userCreatorValue != null">
+ and label_value like CONCAT('%',#{userCreatorValue}, '%')
+ </if>
+ </where>
+ </select>
+
+
+</mapper>
diff --git
a/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/postgresql/JobHistoryMapper.xml
b/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/postgresql/JobHistoryMapper.xml
index f7e75dea0e..0289141e89 100644
---
a/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/postgresql/JobHistoryMapper.xml
+++
b/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/postgresql/JobHistoryMapper.xml
@@ -172,11 +172,11 @@
<select id="selectJobHistoryStatusForUpdate" flushCache="true"
resultType="java.lang.String">
SELECT
- bdt."status"
+ bdt."status"
FROM
- "linkis_ps_job_history_group_history" bdt
+ "linkis_ps_job_history_group_history" bdt
WHERE
- id = #{jobId} FOR UPDATE
+ id = #{jobId} FOR UPDATE
</select>
<select id="countUndoneTaskNoCreator" useCache="true"
resultType="java.lang.Integer" >
@@ -223,7 +223,7 @@
</update>
<update id="updateJobHistoryCancelById" >
- update linkis_ps_job_history_group_history set status =
'Cancelled' ,error_desc = #{errorDesc}
+ update linkis_ps_job_history_group_history set status = 'Cancelled'
,error_desc = #{errorDesc}
WHERE id IN
<foreach collection="idList" item="id" separator="," open="("
close=")">
#{id}
@@ -232,18 +232,18 @@
<select id="selectFailoverJobHistory" resultMap="jobHistoryMap" >
SELECT a.* FROM linkis_ps_job_history_group_history a
WHERE (
- a.instances = ''
- OR a.instances IS NULL
- OR a.instances NOT IN <foreach collection="instancesMap.keys"
open="(" separator="," close=")" item="key">#{key}</foreach>
- OR EXISTS (
- SELECT 1 FROM
- (
- <foreach collection="instancesMap.entrySet()"
separator="union all" index="key" item="val">
- SELECT #{key} AS instances, #{val} AS registryTime
- </foreach>
- ) b
- WHERE a.instances = b.instances AND a.created_time
<![CDATA[<]]> FROM_UNIXTIME(b.registryTime/1000)
- )
+ a.instances = ''
+ OR a.instances IS NULL
+ OR a.instances NOT IN <foreach collection="instancesMap.keys" open="("
separator="," close=")" item="key">#{key}</foreach>
+ OR EXISTS (
+ SELECT 1 FROM
+ (
+ <foreach collection="instancesMap.entrySet()" separator="union all"
index="key" item="val">
+ SELECT #{key} AS instances, #{val} AS registryTime
+ </foreach>
+ ) b
+ WHERE a.instances = b.instances AND a.created_time <![CDATA[<]]>
FROM_UNIXTIME(b.registryTime/1000)
+ )
)
AND
status IN <foreach collection="statusList" open="(" separator=","
close=")" item="status">#{status}</foreach>
@@ -251,4 +251,43 @@
<if test="limit != null and limit > 0">LIMIT #{limit}</if>
</select>
+
+ <select id="taskDurationTopN" useCache="true" resultMap="jobHistoryMap" >
+ /*slave*/ SELECT * FROM linkis_ps_job_history_group_history
+ <where>
+ <if test="umUser != null">and submit_user = #{umUser}</if>
+ <if test="engineType != null">and engine_type = #{engineType}</if>
+ <if test="startDate != null">and created_time >= #{startDate} AND
created_time <![CDATA[<=]]> #{endDate}</if>
+ </where>
+ ORDER BY EXTRACT(EPOCH FROM AGE(cast(updated_time as timestamp),
cast(created_time as timestamp))) desc
+ </select>
+
+ <select id="taskDurationTopNWithCreatorOnly" useCache="true"
resultMap="jobHistoryMap" >
+ /*slave*/ SELECT * FROM linkis_ps_job_history_group_history
+ <where>
+ <if test="umUser != null">and submit_user = #{umUser}</if>
+ <if test="engineType != null">and engine_type = #{engineType}</if>
+ <if test="startDate != null">and created_time >= #{startDate} AND
created_time <![CDATA[<=]]>#{endDate}
+ </if>
+ <if test="userCreatorKey != null and creator != null">
+ and labels like CONCAT('%"', #{userCreatorKey}::text, '":"%-',
#{creator}::text, '%')
+ </if>
+ </where>
+ ORDER BY EXTRACT(EPOCH FROM AGE(cast(updated_time as timestamp),
cast(created_time as timestamp))) desc
+ </select>
+
+ <select id="taskDurationTopNWithUserCreator" useCache="true"
resultMap="jobHistoryMap" >
+ /*slave*/ SELECT * FROM linkis_ps_job_history_group_history
+ <where>
+ <if test="umUser != null">and submit_user = #{umUser}</if>
+ <if test="engineType != null">and engine_type = #{engineType}</if>
+ <if test="startDate != null">and created_time >= #{startDate} AND
created_time <![CDATA[<=]]>#{endDate}
+ </if>
+ <if test="userCreatorKey != null and userCreatorValue != null">
+ and STRPOS(labels, CONCAT('"', #{userCreatorKey}, '":"',
#{userCreatorValue})) > 0
+ </if>
+ </where>
+ ORDER BY EXTRACT(EPOCH FROM AGE(cast(updated_time as timestamp),
cast(created_time as timestamp))) desc
+ </select>
+
</mapper>
diff --git
a/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/postgresql/JobStatisticsMapper.xml
b/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/postgresql/JobStatisticsMapper.xml
new file mode 100644
index 0000000000..f1dd6e0887
--- /dev/null
+++
b/linkis-public-enhancements/linkis-jobhistory/src/main/resources/mapper/postgresql/JobStatisticsMapper.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+
+<mapper namespace="org.apache.linkis.jobhistory.dao.JobStatisticsMapper">
+
+ <select id="taskExecutionStatisticsWithCreatorOnly" useCache="true"
resultMap="jobStatisticsMap">
+ SELECT COUNT(1) sumcount, COUNT(case WHEN status ='Succeed' then 1
END) succeedcount,
+ COUNT(case WHEN status ='Failed' then 1 END) failedcount,
+ COUNT(case WHEN status ='Cancelled' then 1 END) cancelledcount
+ FROM linkis_ps_job_history_group_history
+ <where>
+ <if test="umUser != null">and submit_user = #{umUser}</if>
+ <if test="engineType != null">and engine_type = #{engineType}</if>
+ <if test="startDate != null">and created_time >= #{startDate} AND
created_time <![CDATA[<=]]> #{endDate}</if>
+ <if test="userCreatorKey != null and creator != null">
+ and labels like CONCAT('%"', #{userCreatorKey}::text, '":"%-',
#{creator}::text, '%')
+ </if>
+ </where>
+ </select>
+
+ <select id="taskExecutionStatisticsWithUserCreator" useCache="true"
resultMap="jobStatisticsMap">
+ SELECT COUNT(1) sumcount, COUNT(case WHEN status ='Succeed' then 1
END) succeedcount,
+ COUNT(case WHEN status ='Failed' then 1 END) failedcount,
+ COUNT(case WHEN status ='Cancelled' then 1 END) cancelledcount
+ FROM linkis_ps_job_history_group_history
+ <where>
+ <if test="umUser != null">and submit_user = #{umUser}</if>
+ <if test="engineType != null">and engine_type = #{engineType}</if>
+ <if test="startDate != null">and created_time >= #{startDate} AND
created_time <![CDATA[<=]]>#{endDate}
+ </if>
+ <if test="userCreatorKey != null and userCreatorValue != null">
+ and STRPOS(labels, CONCAT('"', #{userCreatorKey}, '":"',
#{userCreatorValue})) > 0
+ </if>
+ </where>
+ </select>
+
+ <select id="engineExecutionStatistics" useCache="true"
resultMap="jobStatisticsMap">
+ SELECT COUNT(1) sumcount, COUNT(case WHEN status ='Success' then 1
END) succeedcount,
+ COUNT(case WHEN status ='Failed' then 1 END) failedcount,
+ COUNT(case WHEN status ='ShuttingDown' then 1 END) cancelledcount FROM
+ linkis_cg_ec_resource_info_record
+ <where>
+ <if test="umUser != null">and create_user = #{umUser}</if>
+ <if test="engineType != null">and label_value like CONCAT('%',
#{engineType},'%')</if>
+ <if test="startDate != null">and create_time >= #{startDate} AND
create_time <![CDATA[<=]]> #{endDate}</if>
+ <if test="creator != null">
+ and label_value like CONCAT('%-', #{creator}::text, '%')
+ </if>
+ </where>
+ </select>
+
+ <select id="engineExecutionStatisticsWithUserCreator" useCache="true"
resultMap="jobStatisticsMap">
+ SELECT COUNT(1) sumcount, COUNT(case WHEN status ='Success' then 1
END) succeedcount,
+ COUNT(case WHEN status ='Failed' then 1 END) failedcount,
+ COUNT(case WHEN status ='ShuttingDown' then 1 END) cancelledcount FROM
+ linkis_cg_ec_resource_info_record
+ <where>
+ <if test="umUser != null">and create_user = #{umUser}</if>
+ <if test="engineType != null">and label_value like CONCAT('%',
#{engineType},'%')</if>
+ <if test="startDate != null">and create_time >= #{startDate} AND
create_time <![CDATA[<=]]> #{endDate}</if>
+ <if test="userCreatorValue != null">
+ and label_value like CONCAT('%',#{userCreatorValue}::text, '%')
+ </if>
+ </where>
+ </select>
+
+
+</mapper>
diff --git
a/linkis-public-enhancements/linkis-jobhistory/src/main/scala/org/apache/linkis/jobhistory/service/JobHistoryQueryService.java
b/linkis-public-enhancements/linkis-jobhistory/src/main/scala/org/apache/linkis/jobhistory/service/JobHistoryQueryService.java
index b8731554d4..335ea7cdee 100644
---
a/linkis-public-enhancements/linkis-jobhistory/src/main/scala/org/apache/linkis/jobhistory/service/JobHistoryQueryService.java
+++
b/linkis-public-enhancements/linkis-jobhistory/src/main/scala/org/apache/linkis/jobhistory/service/JobHistoryQueryService.java
@@ -5,16 +5,16 @@
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+
package org.apache.linkis.jobhistory.service;
import org.apache.linkis.governance.common.entity.job.JobRequest;
@@ -53,4 +53,6 @@ public interface JobHistoryQueryService {
void changeObserveInfoById(JobHistory jobHistory);
void clearUndoneTasksByEntranceInstance(EntranceInstanceConfRequest
request, Sender sender);
+
+ List<JobHistory> taskDurationTopN(Date sDate, Date eDate, String username,
String creator, String engineType);
}
diff --git
a/linkis-public-enhancements/linkis-jobhistory/src/main/scala/org/apache/linkis/jobhistory/service/JobStatisticsQueryService.java
b/linkis-public-enhancements/linkis-jobhistory/src/main/scala/org/apache/linkis/jobhistory/service/JobStatisticsQueryService.java
new file mode 100644
index 0000000000..5d11b623ad
--- /dev/null
+++
b/linkis-public-enhancements/linkis-jobhistory/src/main/scala/org/apache/linkis/jobhistory/service/JobStatisticsQueryService.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.linkis.jobhistory.service;
+
+import org.apache.linkis.jobhistory.entity.JobStatistics;
+
+import java.util.Date;
+
+
+public interface JobStatisticsQueryService {
+
+ JobStatistics taskExecutionStatistics(Date startDate, Date endDate, String
username, String creator, String engineType);
+
+ JobStatistics engineExecutionStatistics(Date startDate, Date endDate,
String username, String creator, String engineType);
+}
diff --git
a/linkis-public-enhancements/linkis-jobhistory/src/main/scala/org/apache/linkis/jobhistory/service/impl/JobHistoryQueryServiceImpl.scala
b/linkis-public-enhancements/linkis-jobhistory/src/main/scala/org/apache/linkis/jobhistory/service/impl/JobHistoryQueryServiceImpl.scala
index 5c49be89b7..84b73d6a23 100644
---
a/linkis-public-enhancements/linkis-jobhistory/src/main/scala/org/apache/linkis/jobhistory/service/impl/JobHistoryQueryServiceImpl.scala
+++
b/linkis-public-enhancements/linkis-jobhistory/src/main/scala/org/apache/linkis/jobhistory/service/impl/JobHistoryQueryServiceImpl.scala
@@ -486,4 +486,44 @@ class JobHistoryQueryServiceImpl extends
JobHistoryQueryService with Logging {
}
}
+ override def taskDurationTopN(
+ sDate: Date,
+ eDate: Date,
+ username: String,
+ creator: String,
+ engineType: String
+ ): util.List[JobHistory] = {
+ val result = if (StringUtils.isBlank(creator)) {
+ jobHistoryMapper.taskDurationTopN(sDate, eDate, username, engineType)
+ } else if (StringUtils.isBlank(username)) {
+ val fakeLabel = new UserCreatorLabel
+ jobHistoryMapper.taskDurationTopNWithCreatorOnly(
+ username,
+ fakeLabel.getLabelKey,
+ creator,
+ sDate,
+ eDate,
+ engineType
+ )
+ } else {
+ val fakeLabel = new UserCreatorLabel
+ fakeLabel.setUser(username)
+ fakeLabel.setCreator(creator)
+ val userCreator = fakeLabel.getStringValue
+ Utils.tryCatch(fakeLabel.valueCheck(userCreator)) { t =>
+ logger.info("input user or creator is not correct", t)
+ throw t
+ }
+ jobHistoryMapper.taskDurationTopNWithUserCreator(
+ username,
+ fakeLabel.getLabelKey,
+ userCreator,
+ sDate,
+ eDate,
+ engineType
+ )
+ }
+ result
+ }
+
}
diff --git
a/linkis-public-enhancements/linkis-jobhistory/src/main/scala/org/apache/linkis/jobhistory/service/impl/JobStatisticsQueryServiceImpl.scala
b/linkis-public-enhancements/linkis-jobhistory/src/main/scala/org/apache/linkis/jobhistory/service/impl/JobStatisticsQueryServiceImpl.scala
new file mode 100644
index 0000000000..27b8173d05
--- /dev/null
+++
b/linkis-public-enhancements/linkis-jobhistory/src/main/scala/org/apache/linkis/jobhistory/service/impl/JobStatisticsQueryServiceImpl.scala
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.linkis.jobhistory.service.impl
+
+import org.apache.linkis.common.utils.{Logging, Utils}
+import org.apache.linkis.jobhistory.dao.JobStatisticsMapper
+import org.apache.linkis.jobhistory.entity.JobStatistics
+import org.apache.linkis.jobhistory.service.JobStatisticsQueryService
+import org.apache.linkis.manager.label.entity.engine.UserCreatorLabel
+
+import org.apache.commons.lang3.StringUtils
+
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.stereotype.Service
+
+import java.util.Date
+
+@Service
+class JobStatisticsQueryServiceImpl extends JobStatisticsQueryService with
Logging {
+
+ @Autowired
+ private var jobStatisticsMapper: JobStatisticsMapper = _
+
+ override def taskExecutionStatistics(
+ sDate: Date,
+ eDate: Date,
+ username: String,
+ creator: String,
+ engineType: String
+ ): JobStatistics = {
+ val result = if (StringUtils.isBlank(creator)) {
+ jobStatisticsMapper.taskExecutionStatistics(username, sDate, eDate,
engineType)
+ } else if (StringUtils.isBlank(username)) {
+ val fakeLabel = new UserCreatorLabel
+ jobStatisticsMapper.taskExecutionStatisticsWithCreatorOnly(
+ username,
+ fakeLabel.getLabelKey,
+ creator,
+ sDate,
+ eDate,
+ engineType
+ )
+ } else {
+ val fakeLabel = new UserCreatorLabel
+ fakeLabel.setUser(username)
+ fakeLabel.setCreator(creator)
+ val userCreator = fakeLabel.getStringValue
+ Utils.tryCatch(fakeLabel.valueCheck(userCreator)) { t =>
+ logger.info("input user or creator is not correct", t)
+ throw t
+ }
+ jobStatisticsMapper.taskExecutionStatisticsWithUserCreator(
+ username,
+ fakeLabel.getLabelKey,
+ userCreator,
+ sDate,
+ eDate,
+ engineType
+ )
+ }
+ result
+ }
+
+ override def engineExecutionStatistics(
+ sDate: Date,
+ eDate: Date,
+ username: String,
+ creator: String,
+ engineType: String
+ ): JobStatistics = {
+ val result = if (StringUtils.isBlank(username) ||
StringUtils.isBlank(creator)) {
+ jobStatisticsMapper.engineExecutionStatistics(username, creator, sDate,
eDate, engineType)
+ } else {
+ val fakeLabel = new UserCreatorLabel
+ fakeLabel.setUser(username)
+ fakeLabel.setCreator(creator)
+ val userCreator = fakeLabel.getStringValue
+ Utils.tryCatch(fakeLabel.valueCheck(userCreator)) { t =>
+ logger.info("input user or creator is not correct", t)
+ throw t
+ }
+ jobStatisticsMapper.engineExecutionStatisticsWithUserCreator(
+ username,
+ userCreator,
+ sDate,
+ eDate,
+ engineType
+ )
+ }
+ result
+ }
+
+}
diff --git a/linkis-web/package.json b/linkis-web/package.json
index b43a05d183..fbc9566ec7 100644
--- a/linkis-web/package.json
+++ b/linkis-web/package.json
@@ -51,7 +51,8 @@
"vue-router": "3.4.8",
"vuedraggable": "2.24.3",
"vuescroll": "4.16.1",
- "worker-loader": "3.0.8"
+ "worker-loader": "3.0.8",
+ "echarts": "^5.1.1"
},
"devDependencies": {
"@intlify/vue-i18n-loader": "1.0.0",
diff --git a/linkis-web/src/apps/linkis/i18n/common/en.json
b/linkis-web/src/apps/linkis/i18n/common/en.json
index eaec2aa06f..ce5c0da805 100644
--- a/linkis-web/src/apps/linkis/i18n/common/en.json
+++ b/linkis-web/src/apps/linkis/i18n/common/en.json
@@ -90,6 +90,9 @@
"tenant": "Tenant",
"inputTenant": "Please Input Tenant",
"globalSettings": "GlobalSettings",
+ "taskOverTimeTop": "TaskDuration-TOP",
+ "taskTotalNum": "TaskTotalNum",
+ "engineTotalNum":"engineTotalNum",
"resultSet": {
"prefixText": "Because your result set is large, for a better
experience, ",
"linkText": "View result set",
@@ -107,7 +110,7 @@
"resourceManagement": {
"resourceUsage": "Resource usage",
"applicationList": "Applications"
- },
+ },
"time": {
"second": "Second",
"minute": "Minute",
@@ -199,7 +202,8 @@
"EngineConnList": "Engine Conn List",
"opsTool": "OPS Tool",
"userConfig": "User Configuration",
- "configManagement": "Configuration Management"
+ "configManagement": "Configuration Management",
+ "statisticsDashboard": "Statistics Dashboard"
}
}
},
diff --git a/linkis-web/src/apps/linkis/i18n/common/zh.json
b/linkis-web/src/apps/linkis/i18n/common/zh.json
index ba1a8919b8..50f6d2ecf0 100644
--- a/linkis-web/src/apps/linkis/i18n/common/zh.json
+++ b/linkis-web/src/apps/linkis/i18n/common/zh.json
@@ -90,6 +90,9 @@
"tenant": "租户标签",
"inputTenant": "请输入租户标签",
"globalSettings": "全局设置",
+ "taskOverTimeTop": "任务耗时-TOP",
+ "taskTotalNum": "任务总数",
+ "engineTotalNum":"引擎总数",
"resultSet": {
"prefixText": "因为您的结果集较大,为了更好的体验,",
"linkText": "点击查看结果集",
@@ -199,7 +202,8 @@
"EngineConnList": "引擎列表",
"opsTool": "运维工具",
"userConfig": "用户配置",
- "configManagement": "配置项管理"
+ "configManagement": "配置项管理",
+ "statisticsDashboard": "统计看板"
}
}
},
diff --git a/linkis-web/src/apps/linkis/module/statisticsDashboard/index.js
b/linkis-web/src/apps/linkis/module/statisticsDashboard/index.js
new file mode 100644
index 0000000000..1bec7a05b4
--- /dev/null
+++ b/linkis-web/src/apps/linkis/module/statisticsDashboard/index.js
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+export default {
+ name: 'StatisticsDashboard',
+ dispatchs: {
+ Workbench: ['add'],
+ },
+ component: () => import('./index.vue'),
+};
diff --git a/linkis-web/src/apps/linkis/module/statisticsDashboard/index.scss
b/linkis-web/src/apps/linkis/module/statisticsDashboard/index.scss
new file mode 100644
index 0000000000..3a042ec069
--- /dev/null
+++ b/linkis-web/src/apps/linkis/module/statisticsDashboard/index.scss
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@import '@/common/style/variables.scss';
+.progress-wrap {
+ position: $relative;
+ height: 20px;
+ display: flex;
+ align-items: center;
+ font-size: 10px;
+ background: $background-color-base;
+ border-radius: 10px;
+ .progress-busy {
+ background: $success-color;
+ height: 100%;
+ border-radius: 10px;
+ position: $absolute;
+ z-index: 0;
+ }
+ .progress-label {
+ width: 100%;
+ z-index: 1;
+ }
+}
+.global-history {
+ position: $relative;
+ height: 100%;
+ overflow-x: hidden;
+ .global-history-searchbar {
+ position: $relative;
+ .float-right {
+ position: $absolute;
+ right: 10px;
+ }
+ }
+ .ivu-form {
+ display: flex;
+ .ivu-form-item {
+ margin-right: 4px;
+ margin-bottom: 10px;
+ .ivu-form-item-content {
+ display: flex !important;
+ }
+ }
+ .ivu-input-with-suffix {
+ padding-right: 7px;
+ }
+ }
+ .global-history-table {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-top: 16px;
+ .ivu-table th {
+ background-color: $table-thead-blue-bg;
+ color: $body-background;
+ }
+ }
+ .global-history-loading {
+ animation: ani-demo-spin 1s linear infinite;
+ }
+ .divider {
+ margin-top: 7px;
+ height: 20px;
+ }
+ .global-history-page {
+ margin-top: 10px;
+ width: 100%;
+ text-align: center;
+ }
+}
+.datepicker {
+ .ivu-picker-panel-body {
+ background-color: $background-color-white;
+ }
+ .ivu-icon {
+ display: none;
+ }
+}
+.workbench-log-view {
+ height: calc(100% - 76px) !important;
+ .log-tools {
+ height: 36px;
+ line-height: 36px;
+ padding-left: 10px;
+ background: $background-color-base;
+ position: $relative;
+ border-bottom: 2px solid $border-color-base;
+ overflow: hidden;
+ margin-bottom: -2px;
+ .log-tools-control {
+ display: inline-block;
+ position: $absolute;
+ top: 2px;
+ .log-tabs {
+ display: inline-block;
+ position: $absolute;
+ }
+ .log-search {
+ width: 100px;
+ position: $absolute;
+ left: 350px;
+ top: 5px;
+ font-size: $font-size-small;
+ }
+ .err-badge {
+ background: $error-color !important;
+ }
+ .warn-badge {
+ background: $yellow-color !important;
+ }
+ }
+ }
+}
+
+.render-btn {
+ padding: 1px 0 2px 0 !important;
+}
+.pie-content{
+ width: 100%;
+ height: 280px;
+ display: flex;
+ justify-content: space-around;
+ overflow:hidden;
+ min-width: 1000px;
+ padding:10px 0;
+ .pie-chart{
+ width: 42%;
+ min-width: 500px;
+ max-width: 700px;
+ height: 100%;
+ }
+}
+.global-history-title{
+ font-size: 16px;
+ color: #6379bb;
+}
+::v-deep .we-table-wrap{
+ border: 1px solid #dcdee2;
+}
+::v-deep .we-table-wrap .we-table{
+ border:none
+}
\ No newline at end of file
diff --git a/linkis-web/src/apps/linkis/module/statisticsDashboard/index.vue
b/linkis-web/src/apps/linkis/module/statisticsDashboard/index.vue
new file mode 100644
index 0000000000..16f2c09a6e
--- /dev/null
+++ b/linkis-web/src/apps/linkis/module/statisticsDashboard/index.vue
@@ -0,0 +1,786 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<template>
+ <div class="statistics-dashboard">
+ <Form
+ class="statistics-dashboard-searchbar"
+ :model="searchBar"
+ inline
+ >
+ <FormItem
+ prop="shortcut"
+ :label="$t('message.linkis.formItems.date.label')"
+ >
+ <DatePicker
+ :transfer="true"
+ class="datepicker"
+ :options="shortcutOpt"
+ v-model="searchBar.shortcut"
+ type="daterange"
+ placement="bottom-start"
+ format="yyyy-MM-dd"
+ :placeholder="$t('message.linkis.formItems.date.placeholder')"
+ style="width: 175px"
+ :editable="false"
+ />
+ </FormItem>
+ <FormItem prop="creator"
:label="$t('message.linkis.formItems.creator.label')">
+ <Input
+ :maxlength="50"
+ v-model="searchBar.creator"
+ :placeholder="$t('message.linkis.formItems.creator.placeholder')"
+ style="width: 120px"
+ />
+ </FormItem>
+ <FormItem prop="proxyUser" :label="$t('message.linkis.userName')">
+ <Input
+ :maxlength="50"
+ v-model="searchBar.proxyUser"
+ :placeholder="$t('message.linkis.searchName')"
+ style="width: 120px"
+ />
+ </FormItem>
+ <FormItem prop="engine"
:label="$t('message.linkis.formItems.engine.label')">
+ <Select v-model="searchBar.engine" style="width: 120px">
+ <Option v-for="(item) in getEngineTypes" :label="item === 'all' ?
$t('message.linkis.engineTypes.all'): item" :value="item" :key="item" />
+ </Select>
+ </FormItem>
+ <FormItem>
+ <Button
+ type="primary"
+ @click="search"
+ style="margin-right: 10px; margin-top: 32px;"
+ >{{ $t('message.linkis.search') }}</Button>
+ <Button
+ type="warning"
+ @click="reset"
+ style="margin-right: 10px; margin-top: 32px;"
+ >{{ $t('message.linkis.clearSearch') }}</Button>
+ </FormItem>
+ </Form>
+ <div class="pie-content">
+ <div
+ id="task"
+ class="pie-chart"
+ ></div>
+ <div
+ id="engine"
+ class="pie-chart"
+ ></div>
+ </div>
+ <div>
+ <div class="statistics-dashboard-title">{{
$t('message.linkis.taskOverTimeTop') }}
+ <InputNumber
+ v-model="pageSetting.pageSize"
+ style="width:80px;"
+ :min="1"
+ :max="100"
+ :activeChange="false"
+ @on-blur="handleBlur"
+ ></InputNumber>
+ </div>
+ <div
+ class="statistics-dashboard-table"
+ :style="{width: '100%', 'height': moduleHeight+'px'}"
+ >
+ <Icon
+ v-show="isLoading"
+ type="ios-loading"
+ size="30"
+ class="statistics-dashboard-loading"
+ />
+ <history-table
+ v-if="!isLoading"
+ :columns="column"
+ :data="list"
+ :height="moduleHeight"
+ :no-data-text="$t('message.linkis.noDataText')"
+ border
+ stripe
+ @checkall="checkChange"
+ @select-change="selectChange"
+ />
+ </div>
+ </div>
+ </div>
+</template>
+<script>
+import storage from '@/common/helper/storage'
+import table from '@/components/virtualTable'
+import mixin from '@/common/service/mixin'
+import api from '@/common/service/api'
+var echarts = require('echarts')
+export default {
+ name: 'StatisticsDashboard',
+ components: {
+ historyTable: table.historyTable,
+ },
+ mixins: [mixin],
+ data() {
+ const today = new Date(new Date().toLocaleDateString())
+ return {
+ list: [],
+ column: [],
+ getEngineTypes: [],
+ isLoading: false,
+ pageSetting: {
+ total: 0,
+ pageSize: 10,
+ current: 1,
+ },
+ searchBar: {
+ creator: '',
+ proxyUser: '',
+ engine: 'all',
+ status: '',
+ shortcut: [today, today],
+ },
+ inputType: 'number',
+ shortcutOpt: {
+ shortcuts: [
+ {
+ text: this.$t('message.linkis.shortcuts.week'),
+ value() {
+ const end = new Date()
+ const start = new Date()
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+ return [start, end]
+ },
+ },
+ {
+ text: this.$t('message.linkis.shortcuts.month'),
+ value() {
+ const end = new Date()
+ const start = new Date()
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+ return [start, end]
+ },
+ },
+ {
+ text: this.$t('message.linkis.shortcuts.threeMonths'),
+ value() {
+ const end = new Date()
+ const start = new Date()
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
+ return [start, end]
+ },
+ },
+ ],
+ },
+ engineTypes: [
+ {
+ label: this.$t('message.linkis.engineTypes.all'),
+ value: 'all'
+ },
+ {
+ label: 'spark',
+ value: 'spark'
+ },
+ {
+ label: 'hive',
+ value: 'hive'
+ },
+ {
+ label: 'pipeline',
+ value: 'pipeline'
+ },
+ {
+ label: 'python',
+ value: 'python'
+ },
+ {
+ label: 'flowexecution',
+ value: 'flowexecution'
+ },
+ {
+ label: 'appjoint',
+ value: 'appjoint'
+ },
+ {
+ label: 'shell',
+ value: 'shell'
+ }
+ ],
+ isLogAdmin: false,
+ isHistoryAdmin: false,
+ isAdminModel: false,
+ moduleHeight: 200,
+ taskChart: [],
+ engineChart: [],
+ }
+ },
+ created() {
+ // Get whether it is a historical administrator(获取是否是历史管理员权限)
+ api.fetch('/jobhistory/governanceStationAdmin', 'get').then((res) => {
+ this.isLogAdmin = res.admin
+ this.isHistoryAdmin = res.historyAdmin
+ })
+ api.fetch('/configuration/engineType', 'get').then((res) => {
+ this.getEngineTypes = ['all', ...res.engineType]
+ })
+ },
+ mounted() {
+ this.init()
+ this.moduleHeight = this.$parent.$el.clientHeight - 480
+ // Monitor window changes and get browser width and height(监听窗口变化,获取浏览器宽高)
+ window.addEventListener('resize', this.getHeight)
+ },
+ beforeDestroy() {
+ // Monitor window changes and get browser width and height(监听窗口变化,获取浏览器宽高)
+ storage.set('last-admin-model', this.isAdminModel)
+ // storage.set('last-searchbar-status', this.searchBar)
+ window.removeEventListener('resize', this.getHeight)
+ },
+ beforeRouteEnter(to, from, next) {
+ if (from.name !== 'viewHistory') {
+ sessionStorage.removeItem('last-admin-model')
+ sessionStorage.removeItem('last-searchbar-status')
+ sessionStorage.removeItem('last-pageSetting-status')
+ }
+ next()
+ },
+ activated() {
+ this.init()
+ },
+ methods: {
+ getHeight() {
+ this.moduleHeight = this.$parent.$el.clientHeight - 480
+ this.taskChart.resize()
+ this.engineChart.resize()
+ },
+ init() {
+ let isAdminModel = storage.get('last-admin-model')
+ const lastSearch = storage.get('last-searchbar-status')
+ const lastPage = storage.get('last-pageSetting-status')
+ if (lastSearch) {
+ if (lastSearch.shortcut[0] && lastSearch.shortcut[1]) {
+ lastSearch.shortcut = [
+ new Date(lastSearch.shortcut[0]),
+ new Date(lastSearch.shortcut[1]),
+ ]
+ } else {
+ const today = new Date(new Date().toLocaleDateString())
+ lastSearch.shortcut = [today, today]
+ }
+ this.searchBar = lastSearch
+ }
+ if (lastPage) {
+ this.pageSetting = lastPage
+ }
+ if (isAdminModel) {
+ this.switchAdmin()
+ } else {
+ this.search()
+ }
+ storage.remove('last-pageSetting-status')
+ },
+ // Click to view historical details log and return results(点击查看历史详情日志和返回结果)
+ async viewHistory(params) {
+ let sourceJson = params.row.sourceJson
+ if (typeof sourceJson === 'string') {
+ try {
+ sourceJson = JSON.parse(sourceJson)
+ } catch (error) {
+ window.console.log(sourceJson)
+ }
+ }
+ let fileName = ''
+ if (sourceJson && sourceJson.scriptPath) {
+ fileName = sourceJson.scriptPath.split('/').pop()
+ }
+ if (sourceJson && sourceJson.nodeName) {
+ fileName = sourceJson.nodeName
+ }
+ const query = {
+ taskID: params.row.taskID,
+ execID: params.row.strongerExecId,
+ status: params.row.status,
+ fileName,
+ }
+ if (this.isAdminModel) {
+ query.proxyUser = params.row.executeUser
+ }
+ storage.set('last-searchbar-status', this.searchBar)
+ storage.set('last-pageSetting-status', this.pageSetting)
+ // Jump to view the history details page(跳转查看历史详情页面)
+ this.$router.push({
+ path: '/console/statisticsDashboardHistory',
+ query,
+ })
+ },
+
+ getParams() {
+ const startDate = this.searchBar.shortcut[0]
+ ? new Date(this.searchBar.shortcut[0].setHours(0, 0, 0, 0))
+ : this.searchBar.shortcut[0]
+ const endDate = this.searchBar.shortcut[1]
+ ? new Date(this.searchBar.shortcut[1].setHours(23, 59, 59, 0))
+ : this.searchBar.shortcut[1]
+ const params = {
+ creator: this.searchBar.creator,
+ proxyUser: this.searchBar.proxyUser,
+ executeApplicationName: this.searchBar.engine,
+ startDate: startDate && startDate.getTime(),
+ endDate: endDate && endDate.getTime(),
+ pageNow: 1,
+ pageSize: this.pageSetting.pageSize
+
+ }
+
+ let { engine, shortcut } = this.searchBar
+ if (engine === 'all') {
+ delete params.executeApplicationName
+ }
+
+ if (!shortcut[0]) {
+ delete params.startDate
+ }
+ if (!shortcut[1]) {
+ delete params.endDate
+ }
+
+ return params
+ },
+ search() {
+ this.isLoading = true
+ let taskTotal = 0
+ let taskSuccess = 0
+ let taskFalied = 0
+ let taskCancelled = 0
+ let countEngine = 0
+ let countEngineSucceed = 0
+ let countEngineFailed = 0
+ let countEngineShutting = 0
+ const params = this.getParams()
+ this.column = this.getColumns()
+ api
+ .fetch('/jobhistory/listDurationTop', params, 'get')
+ .then((rst) => {
+ this.pageSetting.total = rst.totalPage
+ this.isLoading = false
+ this.list = this.getList(rst.tasks)
+ })
+ .catch(() => {
+ this.list = []
+ this.isLoading = false
+ })
+ api
+ .fetch('/jobhistory/jobstatistics/taskCount', params, 'get')
+ .then((rst) => {
+ this.isLoading = false
+ taskTotal = rst.sumCount
+ taskSuccess = rst.succeedCount
+ taskFalied = rst.failedCount
+ taskCancelled = rst.cancelledCount
+ this.taskChart = echarts.init(document.getElementById('task'))
+ this.taskChart.setOption({
+ title: {
+ text: this.$t('message.linkis.taskTotalNum')+'(' + taskTotal +
')',
+ left: 'center',
+ },
+ tooltip: {
+ trigger: 'item',
+ formatter: '{b}:{c}',
+ },
+ legend: {
+ orient: 'vertical',
+ left: 'right',
+ top: 'bottom',
+ itemWidth: 30,
+ formatter: '{name}',
+ textStyle: {
+ color: '#000000',
+ },
+ data: [
+ { name: this.$t('message.linkis.statusType.succeed'), icon:
'rect' },
+ { name: this.$t('message.linkis.statusType.failed'), icon:
'rect' },
+ { name: this.$t('message.linkis.statusType.cancelled'), icon:
'rect' },
+ ],
+ },
+ calculable: true,
+ series: [
+ {
+ name: '',
+ type: 'pie',
+ radius: '55%',
+ center: ['50%', '50%'],
+ //roseType:'angle',
+ label: {
+ normal: {
+ show: true,
+ // position: 'inner',
+ textStyle: {
+ fontWeight: 300,
+ fontSize: 14,
+ color: '#000000',
+ },
+ formatter: '{b}:{c}',
+ },
+ labelLine: { show: true },
+ },
+ data: [
+ { value: taskSuccess, name:
this.$t('message.linkis.statusType.succeed') },
+ { value: taskFalied, name:
this.$t('message.linkis.statusType.failed') },
+ { value: taskCancelled, name:
this.$t('message.linkis.statusType.cancelled') },
+ ],
+ },
+ ],
+ })
+ })
+ .catch(() => {
+ this.isLoading = false
+ })
+ api
+ .fetch('/jobhistory/jobstatistics/engineCount', params, 'get')
+ .then((rst) => {
+ this.isLoading = false
+ countEngine = rst.countEngine
+ countEngineSucceed = rst.countEngineSucceed
+ countEngineFailed = rst.countEngineFailed
+ countEngineShutting = rst.countEngineShutting
+ this.engineChart = echarts.init(document.getElementById('engine'))
+ this.engineChart.setOption({
+ title: {
+ text: this.$t('message.linkis.engineTotalNum')+'(' + countEngine
+ ')',
+ left: 'center',
+ },
+ tooltip: {
+ trigger: 'item',
+ formatter: '{b}:{c}',
+ },
+ legend: {
+ orient: 'vertical',
+ left: 'right',
+ top: 'bottom',
+ itemWidth: 30,
+ formatter: '{name}',
+ textStyle: {
+ color: '#000000',
+ },
+ data: [
+ { name: this.$t('message.linkis.statusType.succeed'), icon:
'rect' },
+ { name: this.$t('message.linkis.statusType.failed') , icon:
'rect' },
+ { name: this.$t('message.linkis.statusType.cancelled') , icon:
'rect' },
+ ],
+ },
+ calculable: true,
+ series: [
+ {
+ name: '',
+ type: 'pie',
+ radius: '55%',
+ center: ['50%', '50%'],
+ //roseType:'angle',
+ label: {
+ normal: {
+ show: true,
+ // position: 'inner',
+ textStyle: {
+ fontWeight: 300,
+ fontSize: 14,
+ color: '#000000',
+ },
+ formatter: '{b}:{c}',
+ },
+ labelLine: { show: true },
+ },
+ data: [
+ { value: countEngineSucceed, name:
this.$t('message.linkis.statusType.succeed') },
+ { value: countEngineFailed, name:
this.$t('message.linkis.statusType.failed') },
+ { value: countEngineShutting, name:
this.$t('message.linkis.statusType.cancelled') },
+ ],
+ },
+ ],
+ })
+ })
+ .catch(() => {
+ this.isLoading = false
+ })
+ },
+ getList(list) {
+ const getFailedReason = (item) => {
+ return item.errCode && item.errDesc
+ ? item.errCode + item.errDesc
+ : item.errCode || item.errDesc || ''
+ }
+ if (!this.isAdminModel) {
+ return list.map((item) => {
+ const paramsJson = JSON.parse(item.paramsJson)
+ let jobName = ''
+ try {
+ if (paramsJson.configuration.startup.etl_job_name) {
+ jobName = paramsJson.configuration.startup.etl_job_name
+ }
+ } catch (e) {
+ jobName = ''
+ }
+ return {
+ disabled:
+ ['Submitted', 'Inited', 'Scheduled', 'Running'].indexOf(
+ item.status
+ ) === -1,
+ taskID: item.taskID,
+ jobName: jobName,
+ strongerExecId: item.strongerExecId,
+ source: item.sourceTailor,
+ executionCode: item.executionCode,
+ status: item.status,
+ costTime: item.costTime,
+ instance: item.instance,
+ engineInstance: item.engineInstance,
+ requestApplicationName: item.requestApplicationName,
+ executeApplicationName: item.executeApplicationName,
+ executeApplicationName2: item.labels
+ .filter((item) => {
+ return item.startsWith('engineType:')
+ })[0]
+ .substring(11),
+ createdTime: item.createdTime,
+ progress: item.progress,
+ failedReason: getFailedReason(item),
+ runType: item.runType,
+ // instance: item.instance
+ }
+ })
+ }
+ return list.map((item) => {
+ const paramsJson = JSON.parse(item.paramsJson)
+ let jobName = ''
+ try {
+ if (paramsJson.configuration.startup.etl_job_name) {
+ jobName = paramsJson.configuration.startup.etl_job_name
+ }
+ } catch (e) {
+ jobName = ''
+ }
+ return Object.assign(item, {
+ disabled:
+ ['Submitted', 'Inited', 'Scheduled', 'Running'].indexOf(
+ item.status
+ ) === -1,
+ executeApplicationName2: item.labels
+ .filter((item) => {
+ return item.startsWith('engineType:')
+ })[0]
+ .substring(11),
+ jobName: jobName,
+ failedReason: getFailedReason(item),
+ source: item.sourceTailor,
+ })
+ })
+ },
+ checkChange(v) {
+ this.list = this.list.map((it) => {
+ it.checked = !it.disabled && v
+ return it
+ })
+ },
+ selectChange() {
+ this.list = this.list.slice(0)
+ },
+ handleBlur(){
+ this.isLoading = true
+ const params = this.getParams()
+ this.column = this.getColumns()
+ api
+ .fetch('/jobhistory/listDurationTop', params, 'get')
+ .then((rst) => {
+ this.pageSetting.total = rst.totalPage
+ this.isLoading = false
+ this.list = this.getList(rst.tasks)
+ })
+ .catch(() => {
+ this.list = []
+ this.isLoading = false
+ })
+ },
+ getColumns() {
+ const column = [
+ {
+ title: '',
+ key: 'checked',
+ align: 'center',
+ width: 60,
+ renderType: 'checkbox',
+ },
+ {
+ title: this.$t('message.linkis.tableColumns.control.title'),
+ key: 'control',
+ fixed: 'right',
+ align: 'center',
+ width: 60,
+ renderType: 'button',
+ renderParams: [
+ {
+ label: this.$t('message.linkis.tableColumns.control.label'),
+ action: this.viewHistory,
+ },
+ ],
+ },
+ {
+ title: this.$t('message.linkis.tableColumns.taskID'),
+ key: 'taskID',
+ align: 'center',
+ width: 80,
+ },
+ {
+ title: this.$t('message.linkis.tableColumns.fileName'),
+ key: 'source',
+ align: 'center',
+ ellipsis: true,
+ width: 160,
+ },
+ {
+ title: this.$t('message.linkis.tableColumns.executionCode'),
+ key: 'executionCode',
+ align: 'center',
+ width: 280,
+ // overflow to show(溢出以...显示)
+ ellipsis: true,
+ // renderType: 'tooltip',
+ },
+ {
+ title: this.$t('message.linkis.tableColumns.status'),
+ key: 'status',
+ align: 'center',
+ width: 164,
+ renderType: 'if',
+ renderParams: {
+ action: this.setRenderType,
+ },
+ },
+ {
+ title: this.$t('message.linkis.tableColumns.costTime'),
+ key: 'costTime',
+ align: 'center',
+ width: 100,
+ renderType: 'convertTime',
+ },
+ {
+ title: this.$t('message.linkis.tableColumns.failedReason'),
+ key: 'failedReason',
+ align: 'center',
+ className: 'history-failed',
+ width: 180,
+ renderType: 'a',
+ renderParams: {
+ hasDoc: this.checkIfHasDoc,
+ action: this.linkTo,
+ },
+ },
+ {
+ title: `${this.$t(
+ 'message.linkis.tableColumns.requestApplicationName'
+ )}/${this.$t('message.linkis.tableColumns.executeApplicationName')}`,
+ key: 'requestApplicationName',
+ align: 'center',
+ width: 140,
+ renderType: 'concat',
+ renderParams: {
+ concatKey: 'executeApplicationName2',
+ },
+ },
+ {
+ title: this.$t('message.linkis.tableColumns.user'),
+ key: 'umUser',
+ align: 'center',
+ width: 80,
+ },
+ {
+ title: 'entrance',
+ key: 'instance',
+ align: 'center',
+ width: 150,
+ },
+ {
+ title: 'engineplugin',
+ key: 'engineInstance',
+ align: 'center',
+ width: 100,
+ },
+ {
+ title: this.$t('message.linkis.tableColumns.createdTime'),
+ key: 'createdTime',
+ align: 'center',
+ width: 150,
+ renderType: 'formatTime',
+ },
+ ]
+ if (!this.isAdminModel) {
+ const index = column.findIndex((item) => item.key === 'umUser')
+ column.splice(index, 1)
+ }
+ return column
+ },
+ reset() {
+ const today = new Date(new Date().toLocaleDateString())
+ this.searchBar = {
+ creator: '',
+ proxyUser: '',
+ engine: 'all',
+ shortcut: [today, today],
+ }
+ this.pageSetting={
+ pageSize: 10,
+ }
+ this.search()
+ },
+ switchAdmin() {
+ if (!this.isLoading) {
+ if (this.isAdminModel) {
+ this.searchBar.id = null
+ this.searchBar.proxyUser = ''
+ }
+ this.isAdminModel = !this.isAdminModel
+ this.search()
+ }
+ },
+ linkTo(params) {
+ this.$router.push({
+ path: '/console/FAQ',
+ query: {
+ errCode: parseInt(params.row.failedReason),
+ isSkip: true,
+ },
+ })
+ },
+ checkIfHasDoc(params) {
+ const errCodeList = [11011, 11012, 11013, 11014, 11015, 11016, 11017]
+ const errCode = parseInt(params.row.failedReason)
+ if (errCodeList.indexOf(errCode) !== -1) {
+ return true
+ }
+ return false
+ },
+ setRenderType(params) {
+ if (params.row.status === 'Running' && params.row.progress !== 0) {
+ return {
+ type: 'Progress',
+ value: params.row.progress,
+ }
+ } else {
+ return {
+ type: 'Tag',
+ value: params.row.status,
+ }
+ }
+ },
+ },
+}
+</script>
+<style src="./index.scss" lang="scss" scoped></style>
diff --git
a/linkis-web/src/apps/linkis/module/statisticsDashboard/statisticsDashboard.vue
b/linkis-web/src/apps/linkis/module/statisticsDashboard/statisticsDashboard.vue
new file mode 100644
index 0000000000..2600cbf868
--- /dev/null
+++
b/linkis-web/src/apps/linkis/module/statisticsDashboard/statisticsDashboard.vue
@@ -0,0 +1,441 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<template>
+ <div class="statistics-dashboard">
+ <Tabs @on-click="onClickTabs">
+ <TabPane name="log" :label="$t('message.linkis.log')"></TabPane>
+ <!-- <TabPane name="detail" :label="$t('message.linkis.detail')"
disabled></TabPane> -->
+ <TabPane name="result" :label="$t('message.linkis.result')"></TabPane>
+ </Tabs>
+ <Button v-if="!isHistoryDetail" class="backButton" type="primary"
@click="back">{{$t('message.linkis.back')}}</Button>
+ <Icon v-show="isLoading" type="ios-loading" size="30"
class="statistics-dashboard-loading" />
+ <log v-if="tabName === 'log'" :logs="logs" :from-line="fromLine"
:script-view-state="scriptViewState" />
+ <result
+ v-if="tabName === 'result'"
+ ref="result"
+ :script="script"
+ :dispatch="dispatch"
+ :visualShow="visualShow"
+ :script-view-state="scriptViewState"
+ :dataWranglerParams="dataWranglerParams"
+ getResultUrl="filesystem"
+ @on-set-change="changeResultSet"
+ @on-analysis="openAnalysisTab"
+ :visualParams="visualParams"
+ />
+ </div>
+</template>
+<script>
+import result from '@/components/consoleComponent/result.vue'
+import log from '@/components/consoleComponent/log.vue'
+import api from '@/common/service/api'
+import mixin from '@/common/service/mixin'
+import util from '@/common/util'
+import { isUndefined } from 'lodash'
+export default {
+ name: 'statisticsDashboardHistory',
+ components: {
+ log,
+ result
+ },
+ mixins: [mixin],
+ props: {},
+ data() {
+ return {
+ hasResultData: false,
+ isLoading: true,
+ tabName: 'log',
+ visualShow: 'table',
+ dataWranglerParams: {},
+ script: {
+ data: '',
+ oldData: '',
+ result: {},
+ steps: [],
+ progress: {},
+ resultList: null,
+ resultSet: 0,
+ params: {},
+ readOnly: false
+ },
+ visualParams: {},
+ scriptViewState: {
+ // topPanelHeight: '250px',
+ bottomContentHeight: 800,
+ topPanelFull: false,
+ showPanel: 'log',
+ bottomPanelFull: false,
+ cacheLogScroll: 0
+ },
+ logs: {
+ all: '',
+ error: '',
+ warning: '',
+ info: ''
+ },
+ fromLine: 1,
+ isAdminModel: false,
+ jobhistoryTask: null
+ }
+ },
+ created() {
+ this.hasResultData = false
+ },
+ mounted() {
+ let taskID = this.$route.query.taskID
+ this.initHistory(taskID)
+ const node = document.getElementsByClassName('statistics-dashboard')[0];
+ this.scriptViewState.bottomContentHeight = node.clientHeight - 85
+ },
+ computed: {
+ isHistoryDetail() {
+ return this.$route.path === '/console/viewHistoryDetail'
+ }
+ },
+ methods: {
+ // The request is triggered when the tab is clicked, and the log is
requested at the beginning, and no judgment is made.(点击tab时触发请求,log初始就请求了,不做判断)
+ onClickTabs(name) {
+ this.tabName = name
+ if (name === 'result') {
+ // Determine whether it is a result set(判断是否为结果集)
+ if (this.hasResultData) return // Determine whether the data has been
obtained, and return directly if it is obtained(判断是否已经获取过数据,获取过则直接返回)
+ if (this.jobhistoryTask && this.jobhistoryTask.resultLocation) {
+ //Determine if there is a resource address, if not, do not send a
request(判断是否有资源地址,如果没有则不发请求)
+ this.getResult(this.jobhistoryTask)
+ } else {
+ this.$Notice.warning({
+ title: this.$t('message.linkis.tip'),
+ desc: this.$t('message.linkis.serverTip')
+ })
+ }
+ }
+ },
+ changeResultSet(data, cb) {
+ const resultSet = isUndefined(data.currentSet)
+ ? this.script.resultSet
+ : data.currentSet
+ const findResult = this.script.resultList[resultSet]
+ const resultPath = findResult && findResult.path
+ const hasResult = Object.prototype.hasOwnProperty.call(
+ this.script.resultList[resultSet],
+ 'result'
+ )
+ if (!hasResult) {
+ const pageSize = 5000
+ const url = '/filesystem/openFile'
+ api
+ .fetch(
+ url,
+ {
+ path: resultPath,
+ pageSize
+ },
+ 'get'
+ )
+ .then(ret => {
+ let result = {}
+ if (ret.metadata && ret.metadata.length >= 500) {
+ result = {
+ headRows: [],
+ bodyRows: [],
+ // If totalLine is null, it will be displayed as
0(如果totalLine是null,就显示为0)
+ total: ret.totalLine ? ret.totalLine : 0,
+ // (If the content is null, it will display no
data)如果内容为null,就显示暂无数据
+ type: ret.fileContent ? ret.type : 0,
+ path: resultPath,
+ current: 1,
+ size: 20,
+ hugeData: true
+ }
+ } else {
+ result = {
+ headRows: ret.metadata,
+ bodyRows: ret.fileContent,
+ // If totalLine is null, it will be displayed as
0(如果totalLine是null,就显示为0)
+ total: ret.totalLine ? ret.totalLine : 0,
+ // If the content is null, it will display no
data(如果内容为null,就显示暂无数据)
+ type: ret.fileContent ? ret.type : 0,
+ path: resultPath,
+ current: 1,
+ size: 20
+ }
+ }
+
+ this.script.resultList[resultSet].result = result
+ this.script.resultSet = resultSet
+ this.script = {
+ ...this.script
+ }
+ cb()
+ })
+ .catch(() => {
+ cb()
+ })
+ } else {
+ this.script.resultSet = resultSet
+ this.script = {
+ ...this.script
+ }
+ cb()
+ }
+ },
+ // Format the array into json form.(将数组格式化成json形式。)
+ openAnalysisTab(type) {
+ this.visualShow = type
+ if (type === 'visual') {
+ this.biLoading = true
+ let rows = this.scriptResult.headRows
+ let model = {}
+ let dates = ['DATE', 'DATETIME', 'TIMESTAMP', 'TIME', 'YEAR']
+ let numbers = [
+ 'TINYINT',
+ 'SMALLINT',
+ 'MEDIUMINT',
+ 'INT',
+ 'INTEGER',
+ 'BIGINT',
+ 'FLOAT',
+ 'DOUBLE',
+ 'DOUBLE PRECISION',
+ 'REAL',
+ 'DECIMAL',
+ 'BIT',
+ 'SERIAL',
+ 'BOOL',
+ 'BOOLEAN',
+ 'DEC',
+ 'FIXED',
+ 'NUMERIC'
+ ]
+ rows.forEach(item => {
+ let sqlType = item.dataType.toUpperCase()
+ let visualType = 'string'
+ if (numbers.indexOf(sqlType) > -1) {
+ visualType = 'number'
+ } else if (dates.indexOf(sqlType) > -1) {
+ visualType = 'date'
+ }
+ model[item.columnName] = {
+ sqlType,
+ visualType,
+ modelType: visualType === 'number' ? 'value' : 'category'
+ }
+ })
+ this.visualParams = {
+ // viewId: id,
+ // projectId,
+ json: {
+ name: `${this.script.fileName.replace(/\./g, '')}${
+ this.script.resultSet
+ }`,
+ model,
+ source: {
+ engineType: 'spark', //engine type(引擎类型)
+ dataSourceType: 'resultset', //Data source types, result sets,
scripts, library tables(数据源类型,结果集、脚本、库表)
+ dataSourceContent: {
+ resultLocation: this.scriptResult.path
+ },
+ creator: 'IDE'
+ }
+ }
+ }
+ } else if (type === 'dataWrangler') {
+ this.dataWranglerParams = {
+ simpleMode: true,
+ showBottomBar: false,
+ importConfig: {
+ dataSourceConfig: {
+ dataSourceType: 'linkis',
+ dataSourceOptions: {
+ taskID: this.work.taskID || this.work.data.history[0].taskID
+ }
+ },
+ config: {
+ myConfig: {
+ resultSetPath: [this.scriptResult.path]
+ },
+ importConfig: {
+ mergeTables: true,
+ limitRows: 5000,
+ pivotTable: false,
+ tableHeaderRows: 1
+ }
+ }
+ }
+ }
+ }
+ },
+ // Get historical details(获取历史详情)
+ async initHistory(jobId) {
+ try {
+ let jobhistory = await api.fetch(`/jobhistory/${jobId}/get`, 'get')
+ const option = jobhistory.task
+ this.jobhistoryTask = option
+ this.script.runType = option.runType
+ if (!jobhistory.task.logPath) {
+ const errCode = jobhistory.task.errCode
+ ? `\n${this.$t('message.linkis.errorCode')}:${
+ jobhistory.task.errCode
+ }`
+ : ''
+ const errDesc = jobhistory.task.errDesc
+ ? `\n${this.$t('message.linkis.errorDescription')}:${
+ jobhistory.task.errDesc
+ }`
+ : ''
+ const info = this.$t('message.linkis.notLog') + errCode + errDesc
+ this.logs = { all: info, error: '', warning: '', info: '' }
+ this.fromLine = 1
+ return
+ }
+ const params = {
+ path: jobhistory.task.logPath
+ }
+ if (this.$route.query.proxyUser) {
+ params.proxyUser = this.$route.query.proxyUser
+ }
+ let openLog = {}
+ if (this.$route.query.status === 'Scheduled' ||
this.$route.query.status === 'Running') {
+ const tempParams = {
+ fromLine: this.fromLine,
+ size: -1,
+ }
+ openLog = await
api.fetch(`/entrance/${this.$route.query.execID}/log`, tempParams, 'get')
+ } else {
+ openLog = await api.fetch('/filesystem/openLog', params, 'get')
+ }
+ if (openLog) {
+ const log = { all: '', error: '', warning: '', info: '' }
+ const convertLogs = util.convertLog(openLog.log)
+ Object.keys(convertLogs).forEach(key => {
+ if (convertLogs[key]) {
+ log[key] += convertLogs[key] + '\n'
+ }
+ })
+ this.logs = log
+ this.fromLine = log['all'].split('\n').length
+ }
+ this.isLoading = false
+ } catch (errorMsg) {
+ window.console.error(errorMsg)
+ this.isLoading = false
+ }
+ },
+ // Get result set content(获取结果集内容)
+ async getResult(option) {
+ this.isLoading = true
+ try {
+ const url1 = `/filesystem/getDirFileTrees`
+ const rst = await api.fetch(
+ url1,
+ {
+ path: option.resultLocation
+ },
+ 'get'
+ )
+ if (rst.dirFileTrees) {
+ // The order of the result set in the background is sorted by string
according to the name of the result set. When displaying, there will be a
problem that the result set cannot be matched, so add
sorting(后台的结果集顺序是根据结果集名称按字符串排序的,展示时会出现结果集对应不上的问题,所以加上排序)
+ let scriptResultList = rst.dirFileTrees.children.sort(
+ (a, b) => parseInt(a.name, 10) - parseInt(b.name, 10)
+ )
+ if (scriptResultList.length) {
+ const currentResultPath = rst.dirFileTrees.children[0].path
+ const url2 = `/filesystem/openFile`
+ api
+ .fetch(
+ url2,
+ {
+ path: currentResultPath,
+ page: 1,
+ pageSize: 5000
+ },
+ 'get'
+ )
+ .then(ret => {
+ let tmpResult = {}
+ if (ret.metadata && ret.metadata.length >= 500) {
+ tmpResult = {
+ headRows: [],
+ bodyRows: [],
+ total: ret.totalLine,
+ type: ret.type,
+ path: currentResultPath,
+ hugeData: true
+ }
+ } else {
+ tmpResult = {
+ headRows: ret.metadata,
+ bodyRows: ret.fileContent,
+ total: ret.totalLine,
+ type: ret.type,
+ path: currentResultPath
+ }
+ }
+ this.script.resultSet = 0
+ this.script.resultList = scriptResultList
+ this.$set(this.script.resultList[0], 'result', {})
+ Object.assign(this.script.resultList[0].result, tmpResult)
+ this.scriptViewState.showPanel = 'result'
+ this.isLoading = false
+ })
+ }
+ this.hasResultData = true
+ } else {
+ // If not returned, set an initialization data(没有返回则设置一个初始化数据)
+ let tmpResult = {
+ headRows: [],
+ bodyRows: [],
+ total: 0,
+ type: '2',
+ path: ''
+ }
+ this.script.resultSet = 0
+ this.script.resultList = [{}]
+ this.$set(this.script.resultList[0], 'result', {})
+ Object.assign(this.script.resultList[0].result, tmpResult)
+ this.scriptViewState.showPanel = 'result'
+ this.isLoading = false
+ }
+ } catch (error) {
+ this.isLoading = false
+ window.console.error(error)
+ }
+ },
+ // go back to the last page(返回上一页)
+ back() {
+ if (this.isLoading) {
+ return this.$Message.warning(this.$t('message.linkis.logLoading'))
+ }
+ this.$router.go(-1)
+ }
+ }
+}
+</script>
+<style lang="scss" scoped>
+
+
+.backButton {
+ position: absolute;
+ top: 0;
+ right: 20px;
+}
+/deep/ .table-div {
+ height: 100% !important;
+}
+</style>
+
diff --git a/linkis-web/src/apps/linkis/router.js
b/linkis-web/src/apps/linkis/router.js
index 9aa3b05a32..70ea0b0454 100644
--- a/linkis-web/src/apps/linkis/router.js
+++ b/linkis-web/src/apps/linkis/router.js
@@ -319,6 +319,26 @@ export default [
publicPage: true,
},
},
+ {
+ name: 'statisticsDashboard',
+ path: 'statisticsDashboard',
+ component: () =>
+ import('./module/statisticsDashboard/index.vue'),
+ meta: {
+ title: 'statisticsDashboard',
+ publicPage: true,
+ },
+ },
+ {
+ name: 'statisticsDashboardDetail',
+ path: 'statisticsDashboardDetail',
+ component: () =>
+ import('./module/statisticsDashboard/statisticsDashboard.vue'),
+ meta: {
+ title: 'statisticsDashboardHistory',
+ publicPage: true,
+ },
+ },
],
},
]
diff --git a/linkis-web/src/apps/linkis/view/linkis/index.vue
b/linkis-web/src/apps/linkis/view/linkis/index.vue
index 07b792801c..6530358eea 100644
--- a/linkis-web/src/apps/linkis/view/linkis/index.vue
+++ b/linkis-web/src/apps/linkis/view/linkis/index.vue
@@ -187,6 +187,13 @@ export default {
),
showSubMenu: true,
},
+ {
+ key: '1-13',
+ name: this.$t(
+
'message.linkis.sideNavList.function.children.statisticsDashboard'
+ ),
+ path: '/console/statisticsDashboard',
+ },
],
},
datasourceNavList: {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]