DataWorks提供了豐富的OpenAPI,您可以根據需要使用DataWorks的OpenAPI等開放能力實現各種業務場景。本文以使用運維中心的OpenAPI與OpenEvent為例,為您示例如何搭建運維大屏。

背景信息

本實踐搭建的運維大屏可滿足以下業務場景的需求:
  • 實時任務的運行監控與節點狀態監控。
  • 非實時任務的一周調度任務數量趨勢、任務完成情況、近一個月運行時長排行、近一個月任務出錯排行、昨日任務類型分布、昨日運行狀態分布等能力。
完成本實踐后搭建的運維大屏如下所示。
在進行本實踐之前,建議您先參考以下鏈接,了解DataWorks的開發平臺基本能力和概念:

準備工作:開啟并配置消息訂閱(OpenEvent)

在進行代碼開發前,您需要先在開放平臺中創建一個開放事件(OpenEvent),操作步驟請參見開啟并配置消息訂閱(OpenEvent)

實踐1:實時任務運行監控

完成準備工作后,以下步驟將介紹如何使用開發平臺來實現實時任務的運行監控。

  1. 后端代碼開發。
    1. 在工程中編寫代碼實現任務運行消息訂閱。
      package com.aliyun.dataworks.demo;
      
      import com.alibaba.fastjson.JSON;
      import com.alibaba.fastjson.JSONObject;
      import com.aliyun.dataworks.services.DataWorksOpenApiClient;
      import com.aliyun.dataworks.services.EventService;
      import com.aliyun.dataworks.utils.Constants;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.PostMapping;
      import org.springframework.web.bind.annotation.RequestBody;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      /**
       * @author dataworks demo
       */
      @RestController
      @RequestMapping("/eventBridge")
      public class OpenEventConsumer {
      
        @Autowired(required = false)
        private DataWorksOpenApiClient dataWorksOpenApiClient;
      
        @Autowired
        private EventService eventService;
      
        /**
         * 接收eventBridge推送過來的消息
         *
         * @param messageContent
         */
        @PostMapping("/consume")
        public void consume(@RequestBody String messageContent) {
          JSONObject jsonObj = JSON.parseObject(messageContent);
          String eventCode = jsonObj.getString(Constants.EVENT_CODE_KEY);
          String messageId = jsonObj.getString(Constants.EVENT_MESSAGE_ID);
          JSONObject jsonObject = jsonObj.getJSONObject(Constants.EVENT_DATA_KEY);
          System.out.println(messageId + "," + eventCode);
          eventService.consumeEventBridge(messageId, eventCode, jsonObject);
        }
      }
                                      
      上述代碼中會調用consumeEventBridge方法來緩存接收到的信息以方便前端調用,consumeEventBridge的實現如下。
      package com.aliyun.dataworks.services;
      
      import com.alibaba.fastjson.JSONObject;
      import com.aliyun.dataworks.utils.Constants;
      import org.springframework.stereotype.Service;
      
      import java.util.HashMap;
      import java.util.Map;
      import java.util.concurrent.ConcurrentHashMap;
      import java.util.concurrent.atomic.AtomicInteger;
      
      /**
       * @author dataworks demo
       */
      @Service
      public class EventService {
      
        /**
         * 大屏實時數據,DEMO代碼存放到內存中,在實際生產環境應該持久化存儲
         */
        private Map<String, AtomicInteger> screenMap = new ConcurrentHashMap();
      
        /**
         * @param messageId
         * @param eventCode
         * @param messageBody
         * @return
         */
        public boolean consumeEventBridge(String messageId, String eventCode, JSONObject messageBody) {
          if (!isWorkbenchEvent(eventCode)) {
            return false;
          }
          AtomicInteger currentStatus = screenMap.get(eventCode);
          if (currentStatus == null) {
            addZero(eventCode);
            currentStatus = screenMap.get(eventCode);
          }
          //DEMO代碼存放到內存中,在實際生產環境應該持久化存儲
          currentStatus.incrementAndGet();
          System.out.println("messageId=" + messageId);
          System.out.println("messageBody=" + messageBody.toJSONString());
          return true;
        }
      
        /**
         * @return
         */
        public Map<String, Integer> getCurrentStatus() {
          AtomicInteger number = screenMap.get("nodeChangeCreated");
          Map<String, Integer> result = new HashMap<>();
          screenMap.keySet().forEach(key -> result.put(key, screenMap.get(key).intValue()));
          return result;
        }
      
        private boolean isWorkbenchEvent(String eventCode) {
          return Constants.INSTANCE_STATUS_CHANGES.equals(eventCode)
            || Constants.NODE_CHANGE_CREATED.equals(eventCode)
            || Constants.NODE_CHANGE_DELETED.equals(eventCode)
            || Constants.NODE_CHANGE_CREATED.equals(eventCode);
        }
      
        private synchronized void addZero(String eventCode) {
          AtomicInteger currentStatus = screenMap.get(eventCode);
          if (currentStatus == null) {
            screenMap.put(eventCode, new AtomicInteger(0));
          }
        }
      }
                                      
    2. 構建一個提供給前端調用以獲取緩存消息的接口getRealTimeNodeChanges。
      package com.aliyun.dataworks.demo;
      
      import com.aliyun.dataworks.dto.GetInstanceStatusStatisticDto;
      import com.aliyun.dataworks.services.EventService;
      import com.aliyun.dataworks.services.WorkbenchOpenApiService;
      import com.aliyuncs.dataworks_public.model.v20200518.*;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.CrossOrigin;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      import java.util.List;
      import java.util.Map;
      
      /**
       * @author dataworks demo
       */
      @RestController
      @RequestMapping("/screen")
      public class WorkbenchScreenController {
      
        @Autowired
        private WorkbenchOpenApiService workbenchOpenApiService;
      
        @Autowired
        private EventService eventService;
      
        /**
         * 獲取節點和任務實時變更數據
         *
         * @return
         */
        @GetMapping("/getRealTimeNodeChanges")
        public Map<String, Integer> getRealTimeNodeChanges() {
          return eventService.getCurrentStatus();
        }
      
      }
                                      
  2. 前端代碼開發。
    前端部分使用儀表盤來表現,將后端接口返回的instanceSuccessCount與instanceFailureCount進行運算獲得任務的運行成功率。示例代碼如下。
    import React from 'react';
    import cn from 'classnames';
    import { Loading } from '@alifd/next';
    import { Gauge } from '@antv/g2plot';
    import * as helpers from '../helpers';
    import * as services from '../services';
    import classes from '../styles/app.module.css';
    
    export interface Props {}
    
    // 劃分刻度,50%以下表示劣,50%-90%為中,90%以上為優
    const ticks = [0, 1 / 2, 9 / 10, 1];
    const color = ['#F4664A', '#FAAD14', '#30BF78'];
    const RealtimeTaskMonitor: React.FunctionComponent<Props> = () => {
      const ref = React.useRef<HTMLDivElement>(null);
      const [percent, setPercent] = React.useState<number | undefined>(undefined);
      const [visible, setVisible] = React.useState(true);
      const [chart, setChart] = React.useState<Gauge>();
      // 獲取后端數據
      const fetchData = async () => {
        try {
          percent !== undefined && await helpers.pause(5000);
          const response = await services.workbench.getRealtimeNodeChanges();
          // 計算任務運行成功率
          let result = response.instanceSuccessCount / (response.instanceSuccessCount + response.instanceFailureCount);
          result = Number(result.toFixed(2));
          setPercent(result);
          chart?.changeData(result);
        } catch (e) {
          console.error(e);
        } finally {
          visible && setVisible(false);
        }
      };
      React.useEffect(() => {
        fetchData();
      }, [
        percent,
        chart,
      ]);
      React.useEffect(() => {
        if (ref.current) {
          const gauge = new Gauge(ref.current, {
            percent: percent || 0.5,
            range: {
              ticks,
              color: ['#F4664A', '#FAAD14', '#30BF78'],
            },
            padding: 'auto',
            indicator: {
              pointer: {
                style: {
                  stroke: '#D0D0D0',
                },
              },
              pin: {
                style: {
                  stroke: '#D0D0D0',
                },
              },
            },
            statistic: {
              title: {
                formatter: (datum) => {
                  const nextPercent = datum?.percent;
                  if (nextPercent < ticks[1]) {
                    return `差(${Math.round(nextPercent * 100)}%)`;
                  }
                  if (nextPercent < ticks[2]) {
                    return `中(${Math.round(nextPercent * 100)}%)`;
                  }
                  return `優(${Math.round(nextPercent * 100)}%)`;
                },
                style: ({ percent }) => {
                  return {
                    fontSize: '36px',
                    lineHeight: 1,
                    color: percent < ticks[1] ? color[0] : percent < ticks[2] ? color[1] : color[2],
                  };
                },
              },
              content: {
                offsetY: 36,
                style: {
                  fontSize: '24px',
                  color: '#4B535E',
                },
                formatter: () => '運行成功率',
              },
            },
          });
          setChart(gauge);
          gauge.render();
          return () => {
            gauge.destroy();
          };
        }
      }, [
        ref.current,
      ]);
      return (
        <Loading className={cn(classes.appLoading)} visible={visible}>
          <div ref={ref} />
        </Loading>
      );
    };
    
    export default RealtimeTaskMonitor;
                            
    說明 上述代碼中使用pause函數,即暫停5秒,5秒后調用一次后端接口以獲取最新的任務運行狀態并刷新前端組件,然后再重新開始調用后端接口。
  3. 完成上述代碼開發后,您可在本地部署并運行工程代碼。部署并運行的操作請參見通用操作:本地部署
完成以上實踐步驟后,您可搭建一個實時任務運行監控的大盤,如下所示。實時任務運行監控

實踐2:實時節點狀態監控

完成準備工作后,以下步驟將介紹如何使用開發平臺來實現實時節點狀態監控。

  1. 后端代碼開發。
    后端部分的實現過程與實時任務運行監控相同,調用的也是同一個接口,代碼示例請參見后端代碼開發
  2. 前端代碼開發。
    前端部分使用了面積圖來展現已創建、已更新與已刪除三種節點狀態的分布情況。示例代碼如下。
    import React from 'react';
    import cn from 'classnames';
    import moment from 'moment';
    import { Loading } from '@alifd/next';
    import { Area } from '@antv/g2plot';
    import * as helpers from '../helpers';
    import * as services from '../services';
    import classes from '../styles/app.module.css';
    
    export interface Props {}
    export interface Point {
      time: string;
      value: number;
      type: string;
    }
    
    const RealtimeNodeMonitor: React.FunctionComponent<Props> = () => {
      const ref = React.useRef(null);
      const [visible, setVisible] = React.useState(true);
      const [data, setData] = React.useState<Point[]>([]);
      const [chart, setChart] = React.useState<Area>();
      const fetchData = async () => {
        try {
          data.length > 0 && await helpers.pause(5000);
          const response = await services.workbench.getRealtimeNodeChanges();
          const time = moment().format('HH:mm:ss');
          const nextData = data.concat([
            { time, value: response.nodeChangeCreated, type: '已創建' },
            { time, value: response.nodeChangeUpdated, type: '已更新' },
            { time, value: response.nodeChangeDeleted, type: '已刪除' },
          ]);
          setData(nextData);
          chart?.changeData(nextData);
        } catch (e) {
          console.error(e);
        } finally {
          visible && setVisible(false);
        }
      };
      React.useEffect(() => {
        fetchData();
      }, [
        data,
        chart,
      ]);
      React.useEffect(() => {
        if (ref.current) {
          const area = new Area(ref.current, {
            data,
            padding: 'auto',
            xField: 'time',
            yField: 'value',
            seriesField: 'type',
          });
          setChart(area);
          area.render();
          return () => {
            area.destroy();
          };
        }
      }, [
        ref.current,
      ]);
      return (
        <Loading className={cn(classes.appLoading)} visible={visible}>
          <div ref={ref} />
        </Loading>
      );
    };
    
    export default RealtimeNodeMonitor;
                            
    說明 上述代碼中使用pause函數,即暫停5秒,5秒后調用一次后端接口以獲取最新的任務運行狀態并刷新前端組件,然后再重新開始調用后端接口。
  3. 完成上述代碼開發后,您可在本地部署并運行工程代碼。部署并運行的操作請參見通用操作:本地部署
完成以上實踐步驟后,您可搭建一個實時節點狀態監控的大盤,如下所示。開放平臺-運維大屏-節點狀態

實踐3:一周調度任務數量趨勢

完成準備工作后,以下步驟將介紹如何使用開發平臺來實現展示一周調度任務數量趨勢。

  1. 后端代碼開發。
    1. 在后端實現一個方法來調用ListInstanceAmount這個API。
      一周調度任務數量趨勢使用了ListInstanceAmount這個API來獲取周期實例數量的趨勢,因此后端代碼開發時您首先需要實現一個方法來調用此API。
      package com.aliyun.dataworks.services;
      
      import com.aliyun.dataworks.dto.GetInstanceStatusStatisticDto;
      import com.aliyun.dataworks.enums.DagType;
      import com.aliyun.dataworks.enums.SchedulerType;
      import com.aliyuncs.dataworks_public.model.v20200518.*;
      import com.aliyuncs.exceptions.ClientException;
      import com.aliyuncs.exceptions.ServerException;
      import com.aliyuncs.utils.StringUtils;
      import org.junit.Assert;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      import java.util.List;
      
      /**
       * @author dataworks demo
       */
      @Service
      public class WorkbenchOpenApiService {
      
        @Autowired
        private DataWorksOpenApiClient dataWorksOpenApiClient;
        /**
         * 幫助文檔 http://bestwisewords.com/document_detail/212602.html
         *
         * @param beginDate
         * @param endDate
         * @param projectId
         * @return {@link ListInstanceAmountResponse.IntanceCounts}
         */
        public List<ListInstanceAmountResponse.IntanceCounts> listInstanceAmount(String beginDate, String endDate,
            Long projectId) {
          Assert.assertNotNull(beginDate);
          Assert.assertNotNull(endDate);
          Assert.assertNotNull(projectId);
          ListInstanceAmountRequest request = new ListInstanceAmountRequest();
          // 開始業務日期,精確到天。該參數需要配置為yyyy-MM-dd'T'HH:mm:ssZ的UTC格式。
          request.setBeginDate(beginDate);
          // 結束業務日期,精確到天。該參數需要配置為yyyy-MM-dd'T'HH:mm:ssZ的UTC格式。
          request.setEndDate(endDate);
          // 提供projectId入參,DataWorks OpenAPI會做相應的權限校驗
          request.setProjectId(projectId);
          try {
            ListInstanceAmountResponse response = dataWorksOpenApiClient.createClient().getAcsResponse(request);
            // 打印出requestId,方便排查問題
            System.out.println(response.getRequestId());
            return response.getInstanceCounts();
          } catch (ServerException e) {
            e.printStackTrace();
          } catch (ClientException e) {
            e.printStackTrace();
            // 請求ID
            System.out.println(e.getRequestId());
            // 錯誤碼
            System.out.println(e.getErrCode());
            // 錯誤信息
            System.out.println(e.getErrMsg());
          }
          return null;
        }
      }
                                      
    1. 實現一個入口供前端調用。
      package com.aliyun.dataworks.demo;
      
      import com.aliyun.dataworks.dto.GetInstanceStatusStatisticDto;
      import com.aliyun.dataworks.services.EventService;
      import com.aliyun.dataworks.services.WorkbenchOpenApiService;
      import com.aliyuncs.dataworks_public.model.v20200518.*;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.CrossOrigin;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      import java.util.List;
      import java.util.Map;
      
      /**
       * @author dataworks demo
       */
      @RestController
      @RequestMapping("/screen")
      public class WorkbenchScreenController {
      
        @Autowired
        private WorkbenchOpenApiService workbenchOpenApiService;
      
        @Autowired
        private EventService eventService;
      
        /**
         * 獲取項目空間實例總量
         *
         * @param beginDate
         * @param endDate
         * @param projectId
         * @return
         */
        @GetMapping("/listInstanceAmount")
        public List<ListInstanceAmountResponse.IntanceCounts> listInstanceAmount(String beginDate, String endDate,
            Long projectId) {
          return workbenchOpenApiService.listInstanceAmount(beginDate, endDate, projectId);
        }
      }
                                      
  2. 前端代碼開發。
    在前端實現一個橫向的柱狀圖并請求后端接口進行渲染。
    import React from 'react';
    import cn from 'classnames';
    import moment from 'moment';
    import { Loading } from '@alifd/next';
    import { Bar } from '@antv/g2plot';
    import type { InstanceAmount } from '../services/workbench';
    import * as services from '../services';
    import classes from '../styles/app.module.css';
    
    export interface Props {
      projectId: number;
    }
    
    const InstanceAmountList: React.FunctionComponent<Props> = (props) => {
      const ref = React.useRef(null);
      const [visible, setVisible] = React.useState(false);
      const [data, setData] = React.useState<InstanceAmount[]>([]);
      const [chart, setChart] = React.useState<Bar>();
      // 獲取后端數據的方法
      const fetchData = async (signal: AbortSignal, projectId: number) => {
        try {
          setVisible(true);
          // 開始時間使用7天前
          const beginDate = moment().subtract(7, 'days').format('yyyy-MM-DDTHH:mm:ssZZ');
          // 結束時間使用今天
          const endDate = moment().format('yyyy-MM-DDTHH:mm:ssZZ');
          const response = await services.workbench.getInstanceAmountList(signal, beginDate, endDate, projectId);
          chart?.changeData(response.map(i => ({ date: moment(i.date).format('YYYY-MM-DD'), count: i.count })));
          setData(response);
        } catch (e) {
          console.error(e);
        } finally {
          setVisible(false);
        }
      };
      // 開始渲染時獲取數據
      React.useEffect(() => {
        const controller = new AbortController();
        props.projectId && fetchData(controller.signal, props.projectId);
        return () => {
          controller.abort();
        };
      }, [
        // 當projectId變化時重新獲取后端數據
        props.projectId,
      ]);
      // 新建一個橫向的柱狀圖
      React.useEffect(() => {
        if (ref.current) {
          const bar = new Bar(ref.current, {
            data,
            xField: 'count',
            yField: 'date',
            barBackground: {
              style: {
                fill: 'rgba(0,0,0,0.1)',
              },
            },
            height: 200,
            maxBarWidth: 10,
          });
          bar.render();
          setChart(bar);
          return () => {
            bar.destroy();
          };
        }
      }, [
        ref.current,
      ]);
      // 渲染組件
      return (
        <Loading className={cn(classes.appLoading)} visible={visible}>
          <div ref={ref} />
        </Loading>
      );
    };
    
    export default InstanceAmountList;
                            
  3. 完成上述代碼開發后,您可在本地部署并運行工程代碼。部署并運行的操作請參見通用操作:本地部署
完成以上實踐步驟后,您可搭建一個一周調度任務數量趨勢的大盤,如下所示。調度任務數趨勢

實踐4:任務完成情況

完成準備工作后,以下步驟將介紹任務完成情況的整個實現過程。

  1. 后端代碼開發。
    1. 在后端實現一個方法來調用ListSuccessInstanceAmount這個API。
      任務完成情況使用了ListSuccessInstanceAmount,因此后端代碼開發時您首先需要實現一個方法來調用此API。
      package com.aliyun.dataworks.services;
      
      import com.aliyun.dataworks.dto.GetInstanceStatusStatisticDto;
      import com.aliyun.dataworks.enums.DagType;
      import com.aliyun.dataworks.enums.SchedulerType;
      import com.aliyuncs.dataworks_public.model.v20200518.*;
      import com.aliyuncs.exceptions.ClientException;
      import com.aliyuncs.exceptions.ServerException;
      import com.aliyuncs.utils.StringUtils;
      import org.junit.Assert;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      import java.util.List;
      
      /**
       * @author dataworks demo
       */
      @Service
      public class WorkbenchOpenApiService {
      
        @Autowired
        private DataWorksOpenApiClient dataWorksOpenApiClient;
      
        /**
         * 幫助文檔 http://bestwisewords.com/document_detail/212622.html
         * 提供projectId入參,DataWorks OpenAPI會做相應的權限校驗
         *
         * @param projectId
         * @return {@link ListSuccessInstanceAmountResponse.InstanceStatusTrend}
         */
        public ListSuccessInstanceAmountResponse.InstanceStatusTrend listSuccessInstanceAmount(Long projectId) {
          Assert.assertNotNull(projectId);
          ListSuccessInstanceAmountRequest request = new ListSuccessInstanceAmountRequest();
          // 提供projectId入參,DataWorks OpenAPI會做相應的權限校驗
          request.setProjectId(projectId);
          try {
            ListSuccessInstanceAmountResponse response = dataWorksOpenApiClient.createClient().getAcsResponse(request);
            // 打印出requestId,方便排查問題
            System.out.println(response.getRequestId());
            return response.getInstanceStatusTrend();
          } catch (ServerException e) {
            e.printStackTrace();
          } catch (ClientException e) {
            e.printStackTrace();
            // 請求ID
            System.out.println(e.getRequestId());
            // 錯誤碼
            System.out.println(e.getErrCode());
            // 錯誤信息
            System.out.println(e.getErrMsg());
          }
          return null;
        }
      }
                                      
    1. 實現一個入口供前端調用。
      package com.aliyun.dataworks.demo;
      
      import com.aliyun.dataworks.dto.GetInstanceStatusStatisticDto;
      import com.aliyun.dataworks.services.EventService;
      import com.aliyun.dataworks.services.WorkbenchOpenApiService;
      import com.aliyuncs.dataworks_public.model.v20200518.*;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.CrossOrigin;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      import java.util.List;
      import java.util.Map;
      
      /**
       * @author dataworks demo
       */
      @RestController
      @RequestMapping("/screen")
      public class WorkbenchScreenController {
      
        @Autowired
        private WorkbenchOpenApiService workbenchOpenApiService;
      
        @Autowired
        private EventService eventService;
      
        /**
         * 獲取任務成功量的趨勢圖數據
         *
         * @param projectId
         * @return {@link ListSuccessInstanceAmountResponse.InstanceStatusTrend}
         */
        @GetMapping("/listSuccessInstanceAmount")
        public ListSuccessInstanceAmountResponse.InstanceStatusTrend listSuccessInstanceAmount(Long projectId) {
          return workbenchOpenApiService.listSuccessInstanceAmount(projectId);
        }
      }
                                      
  2. 前端代碼開發。
    在前端實現一個折線圖組件來獲取并加載數據。
    import React from 'react';
    import cn from 'classnames';
    import { Loading } from '@alifd/next';
    import { Line } from '@antv/g2plot';
    import * as services from '../services';
    import type { SuccessInstanceAmount } from '../services/workbench';
    import classes from '../styles/app.module.css';
    
    export interface Props {
      projectId: number;
    }
    export interface Point extends SuccessInstanceAmount {
      type?: string;
    }
    
    const SuccessInstanceAmountList: React.FunctionComponent<Props> = (props) => {
      const ref = React.useRef(null);
      const [visible, setVisible] = React.useState(false);
      const [data, setData] = React.useState<Point[]>([]);
      const [chart, setChart] = React.useState<Line>();
      // 獲取數據的方法
      const fetchData = async (signal: AbortSignal, projectId: number) => {
        try {
          setVisible(true);
          const response = await services.workbench.getSuccessInstanceAmountList(signal, projectId);
          let collection: Point[] = [];
          // 把數據結構拍平以進行繪制
          collection = collection.concat(response.avgTrend.map(i => ({ ...i, type: '平均值' })));
          collection = collection.concat(response.todayTrend.map(i => ({ ...i, type: '今日' })));
          collection = collection.concat(response.yesterdayTrend.map(i => ({ ...i, type: '昨日' })));
          // 取最大值來美化Y軸的展示
          const max = Math.max(...collection.map(i => i.count)) + 1;
          chart?.changeData(collection);
          chart?.update({ yAxis: { max } });
          setData(collection);
        } catch (e) {
          console.error(e);
        } finally {
          setVisible(false);
        }
      };
      // 當首次加載或projectId變化時,重新獲取后端數據并加載
      React.useEffect(() => {
        const controller = new AbortController();
        props.projectId && fetchData(controller.signal, props.projectId);
        return () => {
          controller.abort();
        };
      }, [
        props.projectId,
      ]);
      // 構建折線圖
      React.useEffect(() => {
        if (ref.current) {
          const line = new Line(ref.current, {
            data,
            xField: 'timePoint',
            yField: 'count',
            seriesField: 'type',
            height: 300,
            yAxis: {
              tickInterval: 1,
            },
          });
          setChart(line);
          line.render();
          return () => {
            line.destroy();
          };
        }
      }, [
        ref.current,
      ]);
      // 渲染組件
      return (
        <Loading className={cn(classes.appLoading)} visible={visible}>
          <div ref={ref} />
        </Loading>
      );
    };
    
    export default SuccessInstanceAmountList;
                            
  3. 完成上述代碼開發后,您可在本地部署并運行工程代碼。部署并運行的操作請參見通用操作:本地部署
完成以上實踐步驟后,您可搭建一個任務完成情況的大盤,如下所示。任務完成情況

實踐5:近一個月運行時長排行

完成準備工作后,以下步驟將介紹近一個月運行時長排行的整個實現過程。

  1. 后端代碼開發。
    1. 在后端構建了一個方法來處理入參并發送請求給TopTenElapsedTimeInstance這個API。
      package com.aliyun.dataworks.services;
      
      import com.aliyun.dataworks.dto.GetInstanceStatusStatisticDto;
      import com.aliyun.dataworks.enums.DagType;
      import com.aliyun.dataworks.enums.SchedulerType;
      import com.aliyuncs.dataworks_public.model.v20200518.*;
      import com.aliyuncs.exceptions.ClientException;
      import com.aliyuncs.exceptions.ServerException;
      import com.aliyuncs.utils.StringUtils;
      import org.junit.Assert;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      import java.util.List;
      
      /**
       * @author dataworks demo
       */
      @Service
      public class WorkbenchOpenApiService {
      
        @Autowired
        private DataWorksOpenApiClient dataWorksOpenApiClient;
      
        /**
         * 幫助文檔 http://bestwisewords.com/document_detail/212579.html
         *
         * @param projectId
         * @return {@link TopTenElapsedTimeInstanceResponse.InstanceConsumeTimeRank}
         */
        public TopTenElapsedTimeInstanceResponse.InstanceConsumeTimeRank topTenElapsedTimeInstance(Long projectId) {
          Assert.assertNotNull(projectId);
          TopTenElapsedTimeInstanceRequest request = new TopTenElapsedTimeInstanceRequest();
          // 提供projectId入參,DataWorks OpenAPI會做相應的權限校驗
          request.setProjectId(projectId);
          try {
            TopTenElapsedTimeInstanceResponse response = dataWorksOpenApiClient.createClient().getAcsResponse(request);
            // 打印出requestId,方便排查問題
            System.out.println(response.getRequestId());
            return response.getInstanceConsumeTimeRank();
          } catch (ServerException e) {
            e.printStackTrace();
          } catch (ClientException e) {
            e.printStackTrace();
            // 請求ID
            System.out.println(e.getRequestId());
            // 錯誤碼
            System.out.println(e.getErrCode());
            // 錯誤信息
            System.out.println(e.getErrMsg());
          }
          return null;
        }
      }
                                      
    1. 實現一個入口供前端調用。
      package com.aliyun.dataworks.demo;
      
      import com.aliyun.dataworks.dto.GetInstanceStatusStatisticDto;
      import com.aliyun.dataworks.services.EventService;
      import com.aliyun.dataworks.services.WorkbenchOpenApiService;
      import com.aliyuncs.dataworks_public.model.v20200518.*;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.CrossOrigin;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      import java.util.List;
      import java.util.Map;
      
      /**
       * @author dataworks demo
       */
      @RestController
      @RequestMapping("/screen")
      public class WorkbenchScreenController {
      
        @Autowired
        private WorkbenchOpenApiService workbenchOpenApiService;
      
        @Autowired
        private EventService eventService;
      
        /**
         * 獲取近一個月運行時長topN排行
         *
         * @param projectId
         * @return
         */
        @GetMapping("/topTenElapsedTimeInstance")
        public TopTenElapsedTimeInstanceResponse.InstanceConsumeTimeRank topTenElapsedTimeInstance(Long projectId) {
          return workbenchOpenApiService.topTenElapsedTimeInstance(projectId);
        }
      }
                                      
  2. 前端代碼開發。
    在前端選擇表格組件來展示數據。
    import React from 'react';
    import moment from 'moment';
    import { Table } from '@alifd/next';
    import * as services from '../services';
    import type { ConsumeTimeRank } from '../services/workbench';
    
    export interface Props {
      projectId: number;
    }
    
    const { Column } = Table;
    const TopNInstanceElapsedTime: React.FunctionComponent<Props> = (props) => {
      const [visible, setVisible] = React.useState(false);
      const [dataSource, setDataSource] = React.useState<ConsumeTimeRank[]>([]);
      // 獲取后端數據的方法
      const fetchData = async (signal: AbortSignal, projectId: number) => {
        try {
          setVisible(true);
          const response = await services.workbench.getTopNInstanceElapsedTime(signal, projectId);
          setDataSource(response.consumeTimeRank);
        } catch (e) {
          console.error(e);
        } finally {
          setVisible(false);
        }
      };
      // 當初次渲染或projectId變化時,重新調用接口獲取數據并渲染
      React.useEffect(() => {
        const controller = new AbortController();
        props.projectId && fetchData(controller.signal, props.projectId);
        return () => {
          controller.abort();
        };
      }, [
        props.projectId,
      ]);
      // 選染組件
      return (
        <Table
          loading={visible}
          dataSource={dataSource}
          maxBodyHeight={400}
          fixedHeader
        >
          <Column dataIndex="nodeId" title="節點ID" />
          <Column dataIndex="nodeName" title="節點名稱" />
          <Column dataIndex="instanceId" title="實例ID" />
          <Column dataIndex="owner" title="負責人" />
          <Column dataIndex="businessDate" cell={value => moment(value).format('YYYY-MM-DD')} title="業務日期" />
          <Column dataIndex="consumed" title="運行時長" />
        </Table>
      );
    };
    
    export default TopNInstanceElapsedTime;
                            
  3. 完成上述代碼開發后,您可在本地部署并運行工程代碼。部署并運行的操作請參見通用操作:本地部署
完成以上實踐步驟后,您可搭建一個近一個月運行時長排行的大盤,如下所示。月運行時長排行

實踐6:近一個月任務出錯排行

完成準備工作后,以下步驟將介紹近一個月任務出錯排行的整個實現過程。

  1. 后端代碼開發。
    1. 在后端構建了一個方法來處理入參并發送請求給TopTenErrorTimesInstance這個API。
      package com.aliyun.dataworks.services;
      
      import com.aliyun.dataworks.dto.GetInstanceStatusStatisticDto;
      import com.aliyun.dataworks.enums.DagType;
      import com.aliyun.dataworks.enums.SchedulerType;
      import com.aliyuncs.dataworks_public.model.v20200518.*;
      import com.aliyuncs.exceptions.ClientException;
      import com.aliyuncs.exceptions.ServerException;
      import com.aliyuncs.utils.StringUtils;
      import org.junit.Assert;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      import java.util.List;
      
      /**
       * @author dataworks demo
       */
      @Service
      public class WorkbenchOpenApiService {
      
        @Autowired
        private DataWorksOpenApiClient dataWorksOpenApiClient;
      
        /**
         * 幫助文檔 http://bestwisewords.com/document_detail/212587.html
         *
         * @param projectId
         * @return {@link TopTenErrorTimesInstanceResponse.InstanceErrorRank}
         */
        public TopTenErrorTimesInstanceResponse.InstanceErrorRank topTenErrorTimesInstance(Long projectId) {
          TopTenErrorTimesInstanceRequest request = new TopTenErrorTimesInstanceRequest();
          request.setProjectId(projectId);
          try {
            TopTenErrorTimesInstanceResponse response = dataWorksOpenApiClient.createClient().getAcsResponse(request);
            // 打印出requestId,方便排查問題
            System.out.println(response.getRequestId());
            return response.getInstanceErrorRank();
          } catch (ServerException e) {
            e.printStackTrace();
          } catch (ClientException e) {
            e.printStackTrace();
            // 請求ID
            System.out.println(e.getRequestId());
            // 錯誤碼
            System.out.println(e.getErrCode());
            // 錯誤信息
            System.out.println(e.getErrMsg());
          }
          return null;
        }
      }
                                      
    1. 實現一個入口供前端調用。
      package com.aliyun.dataworks.demo;
      
      import com.aliyun.dataworks.dto.GetInstanceStatusStatisticDto;
      import com.aliyun.dataworks.services.EventService;
      import com.aliyun.dataworks.services.WorkbenchOpenApiService;
      import com.aliyuncs.dataworks_public.model.v20200518.*;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.CrossOrigin;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      import java.util.List;
      import java.util.Map;
      
      /**
       * @author dataworks demo
       */
      @RestController
      @RequestMapping("/screen")
      public class WorkbenchScreenController {
      
        @Autowired
        private WorkbenchOpenApiService workbenchOpenApiService;
      
        @Autowired
        private EventService eventService;
      
        /**
         * 獲取任務運行錯誤次數topN排行
         *
         * @param projectId
         * @return
         */
        @GetMapping("/topTenErrorTimesInstance")
        public TopTenErrorTimesInstanceResponse.InstanceErrorRank topTenErrorTimesInstance(Long projectId) {
          return workbenchOpenApiService.topTenErrorTimesInstance(projectId);
        }
      }
                                      
  2. 前端代碼開發。
    在前端選擇表格組件來展示數據。
    import React from 'react';
    import { Table } from '@alifd/next';
    import * as services from '../services';
    import type { ErrorInstance } from '../services/workbench';
    
    export interface Props {
      projectId: number;
    }
    
    const { Column } = Table;
    const TopNErrorInstance: React.FunctionComponent<Props> = (props) => {
      const [visible, setVisible] = React.useState(false);
      const [dataSource, setDataSource] = React.useState<ErrorInstance[]>([]);
      // 獲取數據的方法
      const fetchData = async (signal: AbortSignal, projectId: number) => {
        try {
          setVisible(true);
          const response = await services.workbench.getTopNErrorInstance(signal, projectId);
          setDataSource(response.errorRank);
        } catch (e) {
          console.error(e);
        } finally {
          setVisible(false);
        }
      };
      // 初次渲染或projectId變化時重新調用接口并更新渲染
      React.useEffect(() => {
        const controller = new AbortController();
        props.projectId && fetchData(controller.signal, props.projectId);
        return () => {
          controller.abort();
        };
      }, [
        props.projectId,
      ]);
      // 泫染組件
      return (
        <Table
          loading={visible}
          dataSource={dataSource}
          maxBodyHeight={400}
          fixedHeader
        >
          <Column dataIndex="nodeId" title="節點ID" />
          <Column dataIndex="nodeName" title="節點名稱" />
          <Column dataIndex="owner" title="負責人" />
          <Column
            dataIndex="programType"
            title="任務類型"
            cell={(value: number) => {
              switch (value) {
                case 6:
                  return 'Shell';
                case 10:
                  return 'ODPS SQL';
                case 11:
                  return 'ODPS MR';
                case 23:
                  return '數據集成';
                case 24:
                  return 'ODPS Script';
                case 99:
                  return '虛擬節點';
                case 221:
                  return 'PyODPS 2';
                case 225:
                  return 'ODPS Spark';
                case 227:
                  return 'EMR Hive';
                case 228:
                  return 'EMR Spark';
                case 229:
                  return 'EMR Spark SQL';
                case 230:
                  return 'EMR MR';
                case 239:
                  return 'OSS對象檢查';
                case 257:
                  return 'EMR Shell';
                case 258:
                  return 'EMR Spark Shell';
                case 259:
                  return 'EMR Presto';
                case 260:
                  return 'EMR Impala';
                case 900:
                  return '實時同步';
                case 1089:
                  return '跨租戶節點';
                case 1091:
                  return 'Hologres開發';
                case 1093:
                  return 'Hologres SQL';
                case 1100:
                  return '賦值節點';
                case 1221:
                  return 'PyODPS 3';
              }
            }}
          />
          <Column dataIndex="count" title="出錯次數" />
        </Table>
      );
    };
    
    export default TopNErrorInstance;
                            
  3. 完成上述代碼開發后,您可在本地部署并運行工程代碼。部署并運行的操作請參見通用操作:本地部署
完成以上實踐步驟后,您可搭建一個近一個月運行時長排行的大盤,如下所示。月出錯排行

實踐7:昨日任務類型分布

完成準備工作后,以下步驟將介紹昨日任務類型分布的整個實現過程。

  1. 后端代碼開發。
    1. 在后端構建了一個方法來處理入參并發送請求給GetFileTypeStatistic這個API。
      package com.aliyun.dataworks.services;
      
      import com.aliyun.dataworks.dto.GetInstanceStatusStatisticDto;
      import com.aliyun.dataworks.enums.DagType;
      import com.aliyun.dataworks.enums.SchedulerType;
      import com.aliyuncs.dataworks_public.model.v20200518.*;
      import com.aliyuncs.exceptions.ClientException;
      import com.aliyuncs.exceptions.ServerException;
      import com.aliyuncs.utils.StringUtils;
      import org.junit.Assert;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      import java.util.List;
      
      /**
       * @author dataworks demo
       */
      @Service
      public class WorkbenchOpenApiService {
      
        @Autowired
        private DataWorksOpenApiClient dataWorksOpenApiClient;
      
        /**
         * 幫助文檔 http://bestwisewords.com/document_detail/212717.html
         *
         * @param projectId
         * @param projectEnv
         * @return Array of {@link GetFileTypeStatisticResponse.ProgramTypeAndCount}
         */
        public List<GetFileTypeStatisticResponse.ProgramTypeAndCount> getFileTypeStatistic(Long projectId,
            String projectEnv) {
          Assert.assertNotNull(projectId);
          projectEnv = StringUtils.isEmpty(projectEnv) ? "PROD" : projectEnv;
          GetFileTypeStatisticRequest request = new GetFileTypeStatisticRequest();
          request.setProjectId(projectId);
          request.setProjectEnv(projectEnv);
          try {
            GetFileTypeStatisticResponse response = dataWorksOpenApiClient.createClient().getAcsResponse(request);
            // 打印出requestId,方便排查問題
            System.out.println(response.getRequestId());
            return response.getProgramTypeAndCounts();
          } catch (ServerException e) {
            e.printStackTrace();
          } catch (ClientException e) {
            e.printStackTrace();
            // 請求ID
            System.out.println(e.getRequestId());
            // 錯誤碼
            System.out.println(e.getErrCode());
            // 錯誤信息
            System.out.println(e.getErrMsg());
          }
          return null;
        }
      }
                                      
    1. 實現一個入口供前端調用。
      package com.aliyun.dataworks.demo;
      
      import com.aliyun.dataworks.dto.GetInstanceStatusStatisticDto;
      import com.aliyun.dataworks.services.EventService;
      import com.aliyun.dataworks.services.WorkbenchOpenApiService;
      import com.aliyuncs.dataworks_public.model.v20200518.*;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.CrossOrigin;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      import java.util.List;
      import java.util.Map;
      
      /**
       * @author dataworks demo
       */
      @RestController
      @RequestMapping("/screen")
      public class WorkbenchScreenController {
      
        @Autowired
        private WorkbenchOpenApiService workbenchOpenApiService;
      
        @Autowired
        private EventService eventService;
      
        /**
         * 獲取項目空間下文件類型分布情況
         *
         * @param projectId
         * @param projectEnv
         * @return
         */
        @GetMapping("/getFileTypeStatistic")
        public List<GetFileTypeStatisticResponse.ProgramTypeAndCount> getFileTypeStatistic(Long projectId,
            String projectEnv) {
          return workbenchOpenApiService.getFileTypeStatistic(projectId, projectEnv);
        }
      }
                                      
  2. 前端代碼開發。
    在前端選用餅圖來展示數據。
    import React from 'react';
    import { Loading } from '@alifd/next';
    import { Pie } from '@antv/g2plot';
    import cn from 'classnames';
    import * as services from '../services';
    import type { FileStatus } from '../services/workbench';
    import classes from '../styles/app.module.css';
    
    export interface Props {
      projectId: number;
    }
    
    const TaskStatus: React.FunctionComponent<Props> = (props) => {
      const ref = React.useRef(null);
      const [visible, setVisible] = React.useState(false);
      const [data, setData] = React.useState<FileStatus[]>([]);
      const [chart, setChart] = React.useState<Pie>();
      // 獲取后端數據的方法
      const fetchData = async (signal: AbortSignal, projectId: number) => {
        try {
          setVisible(true);
          const response = await services.workbench.getFileTypeStatistic(signal, projectId);
          chart?.changeData(response);
          setData(response);
        } catch (e) {
          console.error(e);
        } finally {
          setVisible(false);
        }
      };
      // 首次渲染或projectId變化時重新獲取數據并渲染
      React.useEffect(() => {
        const controller = new AbortController();
        props.projectId && fetchData(controller.signal, props.projectId);
        return () => {
          controller.abort();
        };
      }, [
        props.projectId,
      ]);
      // 實例化餅圖
      React.useEffect(() => {
        if (ref.current) {
          const pie = new Pie(ref.current, {
            data,
            angleField: 'count',
            colorField: 'programType',
            label: {
              type: 'inner',
              offset: '-50%',
              content: '{value}',
              style: {
                textAlign: 'center',
                fontSize: 18,
              },
            },
            statistic: {
              title: false,
            },
          });
          setChart(pie);
          pie.render();
          return () => {
            pie.destroy();
          };
        }
      }, [
        ref.current,
      ]);
      // 渲染組件
      return (
        <Loading className={cn(classes.appLoading)} visible={visible}>
          <div ref={ref} />
        </Loading>
      );
    };
    
    export default TaskStatus;
                            
  3. 完成上述代碼開發后,您可在本地部署并運行工程代碼。部署并運行的操作請參見通用操作:本地部署
完成以上實踐步驟后,您可搭建一個昨日任務類型分布的大盤,如下所示。昨日任務類型分布

實踐8:昨日運行狀態分布

完成準備工作后,以下步驟將介紹昨日運行狀態分布的整個實現過程。

  1. 后端代碼開發。
    1. 在后端構建了一個方法來處理入參并發送請求給GetInstanceStatusStatistic這個API。
      package com.aliyun.dataworks.services;
      
      import com.aliyun.dataworks.dto.GetInstanceStatusStatisticDto;
      import com.aliyun.dataworks.enums.DagType;
      import com.aliyun.dataworks.enums.SchedulerType;
      import com.aliyuncs.dataworks_public.model.v20200518.*;
      import com.aliyuncs.exceptions.ClientException;
      import com.aliyuncs.exceptions.ServerException;
      import com.aliyuncs.utils.StringUtils;
      import org.junit.Assert;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      import java.util.List;
      
      /**
       * @author dataworks demo
       */
      @Service
      public class WorkbenchOpenApiService {
      
        @Autowired
        private DataWorksOpenApiClient dataWorksOpenApiClient;
      
        /**
         * 幫助文檔 http://bestwisewords.com/document_detail/212637.html
         *
         * @param getInstanceStatusStatisticDto
         * @return
         */
        public GetInstanceStatusStatisticResponse.StatusCount getInstanceStatusStatistic(
            GetInstanceStatusStatisticDto getInstanceStatusStatisticDto) {
          Assert.assertNotNull(getInstanceStatusStatisticDto.getBizDate());
          Assert.assertNotNull(getInstanceStatusStatisticDto.getProjectId());
          String projectEnv = StringUtils.isEmpty(getInstanceStatusStatisticDto.getProjectEnv())
              ? "PROD"
              : getInstanceStatusStatisticDto.getProjectEnv();
          GetInstanceStatusStatisticRequest request = new GetInstanceStatusStatisticRequest();
          request.setBizDate(getInstanceStatusStatisticDto.getBizDate());
          if (getInstanceStatusStatisticDto.getDagType() != null) {
            DagType dagType = DagType.valueOf(getInstanceStatusStatisticDto.getDagType());
            if (dagType != null) {
              request.setDagType(dagType.name());
            }
          }
      
          request.setProjectEnv(projectEnv);
          if (getInstanceStatusStatisticDto.getSchedulerType() != null) {
            SchedulerType schedulerType = SchedulerType.valueOf(getInstanceStatusStatisticDto.getSchedulerType());
            if (schedulerType != null) {
              request.setSchedulerType(schedulerType.name());
            }
          }
          request.setProjectId(getInstanceStatusStatisticDto.getProjectId());
          try {
            GetInstanceStatusStatisticResponse response = dataWorksOpenApiClient.createClient().getAcsResponse(request);
            // 打印出requestId,方便排查問題
            System.out.println(response.getRequestId());
            return response.getStatusCount();
          } catch (ServerException e) {
            e.printStackTrace();
          } catch (ClientException e) {
            e.printStackTrace();
            // 請求ID
            System.out.println(e.getRequestId());
            // 錯誤碼
            System.out.println(e.getErrCode());
            // 錯誤信息
            System.out.println(e.getErrMsg());
          }
          return null;
        }
      }
                                      
    1. 實現一個入口供前端調用。
      package com.aliyun.dataworks.demo;
      
      import com.aliyun.dataworks.dto.GetInstanceStatusStatisticDto;
      import com.aliyun.dataworks.services.EventService;
      import com.aliyun.dataworks.services.WorkbenchOpenApiService;
      import com.aliyuncs.dataworks_public.model.v20200518.*;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.CrossOrigin;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      import java.util.List;
      import java.util.Map;
      
      /**
       * @author dataworks demo
       */
      @RestController
      @RequestMapping("/screen")
      public class WorkbenchScreenController {
      
        @Autowired
        private WorkbenchOpenApiService workbenchOpenApiService;
      
        @Autowired
        private EventService eventService;
      
        /**
         * 獲取項目空間下實例狀態分布
         *
         * @param getInstanceStatusStatisticDto
         * @return
         */
        @GetMapping("/getInstanceStatusStatistic")
        public GetInstanceStatusStatisticResponse.StatusCount getInstanceStatusStatistic(
            GetInstanceStatusStatisticDto getInstanceStatusStatisticDto) {
          return workbenchOpenApiService.getInstanceStatusStatistic(getInstanceStatusStatisticDto);
        }
      }
                                      
  2. 前端代碼開發。
    在前端選用餅圖來展示數據。
    import React from 'react';
    import { Loading } from '@alifd/next';
    import { Pie } from '@antv/g2plot';
    import cn from 'classnames';
    import * as services from '../services';
    import classes from '../styles/app.module.css';
    
    export interface Props {
      projectId: number;
    }
    export interface Point {
      type: string;
      value: number;
    }
    
    const InstanceStatus: React.FunctionComponent<Props> = (props) => {
      const ref = React.useRef(null);
      const [visible, setVisible] = React.useState(false);
      const [data, setData] = React.useState<Point[]>([]);
      const [chart, setChart] = React.useState<Pie>();
      // 獲取后端數據的方法
      const fetchData = async (signal: AbortSignal) => {
        try {
          setVisible(true);
          const nextData: Point[] = [];
          const response = await services.workbench.getInstanceStatus(signal, props.projectId);
          nextData.push({ type: '未運行', value: response.notRunCount });
          nextData.push({ type: '等待中', value: response.waitTimeCount + response.waitResCount });
          nextData.push({ type: '運行中', value: response.runningCount });
          nextData.push({ type: '運行成功', value: response.successCount });
          nextData.push({ type: '運行失敗', value: response.failureCount });
          chart?.changeData(nextData);
          setData(nextData);
        } catch (e) {
          console.error(e);
        } finally {
          setVisible(false);
        }
      };
      // 首次渲染或projectId變化時重新獲取數據并渲染
      React.useEffect(() => {
        const controller = new AbortController();
        props.projectId && fetchData(controller.signal);
        return () => {
          controller.abort();
        };
      }, [
        props.projectId,
      ]);
      // 實例化餅圖
      React.useEffect(() => {
        if (ref.current) {
          const pie = new Pie(ref.current, {
            data,
            angleField: 'value',
            colorField: 'type',
            innerRadius: 0.6,
            label: {
              type: 'inner',
              offset: '-50%',
              content: '{value}',
              style: {
                textAlign: 'center',
                fontSize: 18,
              },
            },
            statistic: {
              title: false,
            },
          });
          setChart(pie);
          pie.render();
          return () => {
            pie.destroy();
          };
        }
      }, [
        ref.current,
      ]);
      // 渲染組件
      return (
        <Loading className={cn(classes.appLoading)} visible={visible}>
          <div ref={ref} />
        </Loading>
      );
    };
    
    export default InstanceStatus;
                            
  3. 完成上述代碼開發后,您可在本地部署并運行工程代碼。部署并運行的操作請參見通用操作:本地部署
完成以上實踐步驟后,您可搭建一個昨日運行狀態分布的大盤,如下所示。昨日運行狀態分布

通用操作:本地部署

  1. 準備依賴環境。
    您需準備好以下依賴環境:java8及以上、maven構建工具、node環境、pnpm工具。您可以執行以下命令來確定是否具備上述環境:
    npm -v // 如果已安裝成功,執行命令將展示版本號,否則會報沒有命令錯誤
    java -version // 如果已安裝成功,執行命令將展示版本號,否則會報沒有命令錯誤
    pnpm -v // 如果已安裝成功,執行命令將展示版本號,否則會報沒有命令錯誤
  2. 下載工程。
    工程下載鏈接:workbench-screen-demo.zip。下載工程后,進入工程中并執行以下命令:
    pnpm i
  3. 在范例工程中的backend/src/main/resources路徑下找到application.properties文件,修改文件中的核心參數。
    • api.access-key-id與api.access-key-secret為您阿里云賬號的AccessKey ID與AccessKey Secret。
      說明 您可以在AccessKey 管理頁面獲取阿里云賬號的相關信息。
    • api.region-id、api.endpoint需修改為待調用OpenAPI的地域信息。
    其他參數可根據實際情況修改,修改后的填寫示例如下。部署示例
  4. 在工程根目錄下執行以下命令,運行示例實踐代碼。
    npm run dev