浏览代码

added Dashboard

Jacky 4 年之前
父节点
当前提交
3bf1655db7

+ 1 - 0
nginx-ui-frontend/.env.development

@@ -1 +1,2 @@
 VUE_APP_API_ROOT = /
+VUE_APP_API_WSS_ROOT =

+ 1 - 0
nginx-ui-frontend/.env.production

@@ -1 +1,2 @@
 VUE_APP_API_ROOT = /api
+VUE_APP_API_WSS_ROOT =

+ 1 - 0
nginx-ui-frontend/package.json

@@ -11,6 +11,7 @@
         "ant-design-vue": "^1.7.3",
         "axios": "^0.21.1",
         "core-js": "^3.9.0",
+        "viser-vue": "^2.4.8",
         "vue": "^2.6.11",
         "vue-itextarea": "^1.0.9",
         "vue-router": "^3.5.1",

+ 62 - 0
nginx-ui-frontend/src/components/Charts/Bar.vue

@@ -0,0 +1,62 @@
+<template>
+  <div :style="{ padding: '0 0 32px 32px' }">
+    <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
+    <v-chart
+      height="254"
+      :data="data"
+      :forceFit="true"
+      :padding="['auto', 'auto', '40', '50']">
+      <v-tooltip />
+      <v-axis />
+      <v-bar position="x*y"/>
+    </v-chart>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Bar',
+  props: {
+    title: {
+      type: String,
+      default: ''
+    },
+    data: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    scale: {
+      type: Array,
+      default: () => {
+        return [{
+          dataKey: 'x',
+          min: 2
+        }, {
+          dataKey: 'y',
+          title: '时间',
+          min: 1,
+          max: 22
+        }]
+      }
+    },
+    tooltip: {
+      type: Array,
+      default: () => {
+        return [
+          'x*y',
+          (x, y) => ({
+            name: x,
+            value: y
+          })
+        ]
+      }
+    }
+  },
+  data () {
+    return {
+    }
+  }
+}
+</script>

+ 110 - 0
nginx-ui-frontend/src/components/Charts/ChartCard.vue

@@ -0,0 +1,110 @@
+<template>
+  <a-card :loading="loading" :body-style="{ padding: '20px 24px 8px' }" :bordered="false">
+    <div class="chart-card-header">
+      <a-statistic :title="title" :precision="precision" :value="total" />
+    </div>
+    <div class="chart-card-content">
+      <div class="content-fix">
+        <slot></slot>
+      </div>
+    </div>
+    <div class="chart-card-footer">
+      <div class="field">
+        <slot name="footer"></slot>
+      </div>
+    </div>
+  </a-card>
+</template>
+
+<script>
+export default {
+  name: 'ChartCard',
+  props: {
+    title: {
+      type: String,
+      default: ''
+    },
+    total: {
+      type: [Function, Number, String],
+      required: false,
+      default: null
+    },
+    loading: {
+      type: Boolean,
+      default: false
+    },
+    precision: {
+      type: Number,
+      default: 0
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chart-card-header {
+    position: relative;
+    overflow: hidden;
+    width: 100%;
+
+    .meta {
+      position: relative;
+      overflow: hidden;
+      width: 100%;
+      color: rgba(0, 0, 0, .45);
+      font-size: 14px;
+      line-height: 22px;
+    }
+  }
+
+  .chart-card-action {
+    cursor: pointer;
+    position: absolute;
+    top: 0;
+    right: 0;
+  }
+
+  .chart-card-footer {
+    border-top: 1px solid #e8e8e8;
+    padding-top: 9px;
+    margin-top: 8px;
+
+    > * {
+      position: relative;
+    }
+
+    .field {
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      margin: 0;
+    }
+  }
+
+  .chart-card-content {
+    margin-bottom: 12px;
+    position: relative;
+    height: 46px;
+    width: 100%;
+
+    .content-fix {
+      position: absolute;
+      left: 0;
+      bottom: 0;
+      width: 100%;
+    }
+  }
+
+  .total {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    word-break: break-all;
+    white-space: nowrap;
+    color: #000;
+    margin-top: 4px;
+    margin-bottom: 0;
+    font-size: 30px;
+    line-height: 38px;
+    height: 38px;
+  }
+</style>

+ 67 - 0
nginx-ui-frontend/src/components/Charts/Liquid.vue

@@ -0,0 +1,67 @@
+<template>
+  <div>
+    <v-chart
+      :forceFit="true"
+      :height="height"
+      :width="width"
+      :data="data"
+      :scale="scale"
+      :padding="0">
+      <v-tooltip />
+      <v-interval
+        :shape="['liquid-fill-gauge']"
+        position="transfer*value"
+        color=""
+        :v-style="{
+          lineWidth: 10,
+          opacity: 0.75
+        }"
+        :tooltip="[
+          'transfer*value',
+          (transfer, value) => {
+            return {
+              name: transfer,
+              value,
+            };
+          },
+        ]"
+      ></v-interval>
+      <v-guide
+        v-for="(row, index) in data"
+        :key="index"
+        type="text"
+        :top="true"
+        :position="{
+          gender: row.transfer,
+          value: 45
+        }"
+        :content="row.value + '%'"
+        :v-style="{
+          fontSize: 100,
+          textAlign: 'center',
+          opacity: 0.75,
+        }"
+      />
+    </v-chart>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Liquid',
+  props: {
+    height: {
+      type: Number,
+      default: 0
+    },
+    width: {
+      type: Number,
+      default: 0
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 51 - 0
nginx-ui-frontend/src/components/Charts/MiniArea.vue

@@ -0,0 +1,51 @@
+<template>
+  <div class="antv-chart-mini">
+    <div class="chart-wrapper" :style="{ height: 46 }">
+      <v-chart :force-fit="true" :height="height" :data="data" :padding="[36, 0, 18, 0]">
+        <v-tooltip/>
+        <v-smooth-area position="x*y"/>
+      </v-chart>
+    </div>
+  </div>
+</template>
+
+<script>
+  const tooltip = [
+    'x*y',
+    (x, y) => ({
+      name: x,
+      value: y
+    })
+  ]
+  const scale = [{
+    dataKey: 'x',
+    min: 2
+  }, {
+    dataKey: 'y',
+    title: '时间',
+    min: 1,
+    max: 22
+  }]
+
+  export default {
+    name: 'MiniArea',
+    props: {
+      data: {
+        type: Array,
+        default: null
+      },
+    },
+    data() {
+      return {
+        dataConfig: this.data,
+        tooltip,
+        scale,
+        height: 100
+      }
+    }
+  }
+</script>
+
+<style lang="less" scoped>
+  @import "chart";
+</style>

+ 37 - 0
nginx-ui-frontend/src/components/Charts/MiniBar.vue

@@ -0,0 +1,37 @@
+<template>
+  <div class="antv-chart-mini">
+    <div class="chart-wrapper" :style="{ height: 46 }">
+      <v-chart :force-fit="true" :height="height" :data="data" :padding="[36, 5, 18, 5]">
+        <v-tooltip/>
+        <v-bar position="x*y"/>
+      </v-chart>
+    </div>
+  </div>
+</template>
+
+<script>
+  const tooltip = [
+    'x*y',
+    (x, y) => ({
+      name: x,
+      value: y
+    })
+  ]
+
+  export default {
+    name: 'MiniBar',
+    props: {
+      data: Array,
+    },
+    data() {
+      return {
+        tooltip,
+        height: 100
+      }
+    }
+  }
+</script>
+
+<style lang="less" scoped>
+  @import "chart";
+</style>

+ 75 - 0
nginx-ui-frontend/src/components/Charts/MiniProgress.vue

@@ -0,0 +1,75 @@
+<template>
+  <div class="chart-mini-progress">
+    <div class="target" :style="{ left: target + '%'}">
+      <span :style="{ backgroundColor: color }" />
+      <span :style="{ backgroundColor: color }"/>
+    </div>
+    <div class="progress-wrapper">
+      <div class="progress" :style="{ backgroundColor: color, width: percentage + '%', height: height }"></div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'MiniProgress',
+  props: {
+    target: {
+      type: Number,
+      default: 0
+    },
+    height: {
+      type: String,
+      default: '10px'
+    },
+    color: {
+      type: String,
+      default: '#13C2C2'
+    },
+    percentage: {
+      type: Number,
+      default: 0
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chart-mini-progress {
+    padding: 5px 0;
+    position: relative;
+    width: 100%;
+
+    .target {
+      position: absolute;
+      top: 0;
+      bottom: 0;
+
+      span {
+        border-radius: 100px;
+        position: absolute;
+        top: 0;
+        left: 0;
+        height: 4px;
+        width: 2px;
+
+        &:last-child {
+          top: auto;
+          bottom: 0;
+        }
+      }
+    }
+    .progress-wrapper {
+      background-color: #f5f5f5;
+      position: relative;
+
+      .progress {
+        transition: all .4s cubic-bezier(.08,.82,.17,1) 0s;
+        border-radius: 1px 0 0 1px;
+        background-color: #1890ff;
+        width: 0;
+        height: 100%;
+      }
+    }
+  }
+</style>

+ 39 - 0
nginx-ui-frontend/src/components/Charts/MiniSmoothArea.vue

@@ -0,0 +1,39 @@
+<template>
+  <div :class="prefixCls">
+    <div class="chart-wrapper" :style="{ height: 46 }">
+      <v-chart :force-fit="true" :height="100" :data="dataSource" :scale="scale" :padding="[36, 0, 18, 0]">
+        <v-tooltip />
+        <v-smooth-line position="x*y" :size="1" />
+        <v-smooth-area position="x*y" />
+      </v-chart>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'MiniSmoothArea',
+  props: {
+    prefixCls: {
+      type: String,
+      default: 'ant-pro-smooth-area'
+    },
+    scale: {
+      type: [Object, Array],
+    },
+    dataSource: {
+      type: Array,
+      required: true
+    }
+  },
+  data () {
+    return {
+      height: 100
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  @import "smooth.area.less";
+</style>

+ 68 - 0
nginx-ui-frontend/src/components/Charts/Radar.vue

@@ -0,0 +1,68 @@
+<template>
+  <v-chart :forceFit="true" height="400" :data="data" :padding="[20, 20, 95, 20]" :scale="scale">
+    <v-tooltip></v-tooltip>
+    <v-axis :dataKey="axis1Opts.dataKey" :line="axis1Opts.line" :tickLine="axis1Opts.tickLine" :grid="axis1Opts.grid" />
+    <v-axis :dataKey="axis2Opts.dataKey" :line="axis2Opts.line" :tickLine="axis2Opts.tickLine" :grid="axis2Opts.grid" />
+    <v-legend dataKey="user" marker="circle" :offset="30" />
+    <v-coord type="polar" radius="0.8" />
+    <v-line position="item*score" color="user" :size="2" />
+    <v-point position="item*score" color="user" :size="4" shape="circle" />
+  </v-chart>
+</template>
+
+<script>
+const axis1Opts = {
+  dataKey: 'item',
+  line: null,
+  tickLine: null,
+  grid: {
+    lineStyle: {
+      lineDash: null
+    },
+    hideFirstLine: false
+  }
+}
+const axis2Opts = {
+  dataKey: 'score',
+  line: null,
+  tickLine: null,
+  grid: {
+    type: 'polygon',
+    lineStyle: {
+      lineDash: null
+    }
+  }
+}
+
+const scale = [
+  {
+    dataKey: 'score',
+    min: 0,
+    max: 80
+  }, {
+    dataKey: 'user',
+    alias: '类型'
+  }
+]
+
+export default {
+  name: 'Radar',
+  props: {
+    data: {
+      type: Array,
+      default: null
+    }
+  },
+  data () {
+    return {
+      axis1Opts,
+      axis2Opts,
+      scale
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 77 - 0
nginx-ui-frontend/src/components/Charts/RankList.vue

@@ -0,0 +1,77 @@
+<template>
+  <div class="rank">
+    <h4 class="title">{{ title }}</h4>
+    <ul class="list">
+      <li :key="index" v-for="(item, index) in list">
+        <span :class="index < 3 ? 'active' : null">{{ index + 1 }}</span>
+        <span>{{ item.name }}</span>
+        <span>{{ item.total }}</span>
+      </li>
+    </ul>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'RankList',
+  // ['title', 'list']
+  props: {
+    title: {
+      type: String,
+      default: ''
+    },
+    list: {
+      type: Array,
+      default: null
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+
+  .rank {
+    padding: 0 32px 32px 72px;
+
+    .list {
+      margin: 25px 0 0;
+      padding: 0;
+      list-style: none;
+
+      li {
+        margin-top: 16px;
+
+        span {
+          color: rgba(0, 0, 0, .65);
+          font-size: 14px;
+          line-height: 22px;
+
+          &:first-child {
+            background-color: #f5f5f5;
+            border-radius: 20px;
+            display: inline-block;
+            font-size: 12px;
+            font-weight: 600;
+            margin-right: 24px;
+            height: 20px;
+            line-height: 20px;
+            width: 20px;
+            text-align: center;
+          }
+          &.active {
+            background-color: #314659;
+            color: #fff;
+          }
+          &:last-child {
+            float: right;
+          }
+        }
+      }
+    }
+  }
+
+  .mobile .rank {
+    padding: 0 32px 32px 32px;
+  }
+
+</style>

+ 113 - 0
nginx-ui-frontend/src/components/Charts/TagCloud.vue

@@ -0,0 +1,113 @@
+<template>
+  <v-chart :width="width" :height="height" :padding="[0]" :data="data" :scale="scale">
+    <v-tooltip :show-title="false" />
+    <v-coord type="rect" direction="TL" />
+    <v-point position="x*y" color="category" shape="cloud" tooltip="value*category" />
+  </v-chart>
+</template>
+
+<script>
+import { registerShape } from 'viser-vue'
+const DataSet = require('@antv/data-set')
+
+const imgUrl = 'https://gw.alipayobjects.com/zos/rmsportal/gWyeGLCdFFRavBGIDzWk.png'
+
+const scale = [
+  { dataKey: 'x', nice: false },
+  { dataKey: 'y', nice: false }
+]
+
+registerShape('point', 'cloud', {
+  draw (cfg, container) {
+    return container.addShape('text', {
+      attrs: {
+        fillOpacity: cfg.opacity,
+        fontSize: cfg.origin._origin.size,
+        rotate: cfg.origin._origin.rotate,
+        text: cfg.origin._origin.text,
+        textAlign: 'center',
+        fontFamily: cfg.origin._origin.font,
+        fill: cfg.color,
+        textBaseline: 'Alphabetic',
+        ...cfg.style,
+        x: cfg.x,
+        y: cfg.y
+      }
+    })
+  }
+})
+
+export default {
+  name: 'TagCloud',
+  props: {
+    tagList: {
+      type: Array,
+      required: true
+    },
+    height: {
+      type: Number,
+      default: 400
+    },
+    width: {
+      type: Number,
+      default: 640
+    }
+  },
+  data () {
+    return {
+      data: [],
+      scale
+    }
+  },
+  watch: {
+    tagList: function (val) {
+      if (val.length > 0) {
+        this.initTagCloud(val)
+      }
+    }
+  },
+  mounted () {
+    if (this.tagList.length > 0) {
+      this.initTagCloud(this.tagList)
+    }
+  },
+  methods: {
+    initTagCloud (dataSource) {
+      const { height, width } = this
+
+      const dv = new DataSet.View().source(dataSource)
+      const range = dv.range('value')
+      const min = range[0]
+      const max = range[1]
+      const imageMask = new Image()
+      imageMask.crossOrigin = ''
+      imageMask.src = imgUrl
+      imageMask.onload = () => {
+        dv.transform({
+          type: 'tag-cloud',
+          fields: ['name', 'value'],
+          size: [width, height],
+          imageMask,
+          font: 'Verdana',
+          padding: 0,
+          timeInterval: 5000, // max execute time
+          rotate () {
+            let random = ~~(Math.random() * 4) % 4
+            if (random === 2) {
+              random = 0
+            }
+            return random * 90 // 0, 90, 270
+          },
+          fontSize (d) {
+            if (d.value) {
+              return ((d.value - min) / (max - min)) * (32 - 8) + 8
+            }
+            return 0
+          }
+        })
+        this.data = dv.rows
+      }
+    }
+  }
+}
+</script>

+ 64 - 0
nginx-ui-frontend/src/components/Charts/TransferBar.vue

@@ -0,0 +1,64 @@
+<template>
+  <div :style="{ padding: '0 0 32px 32px' }">
+    <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
+    <v-chart
+      height="254"
+      :data="data"
+      :scale="scale"
+      :forceFit="true"
+      :padding="['auto', 'auto', '40', '50']">
+      <v-tooltip />
+      <v-axis />
+      <v-bar position="x*y"/>
+    </v-chart>
+  </div>
+</template>
+
+<script>
+const tooltip = [
+  'x*y',
+  (x, y) => ({
+    name: x,
+    value: y
+  })
+]
+const scale = [{
+  dataKey: 'x',
+  title: '日期(天)',
+  alias: '日期(天)',
+  min: 2
+}, {
+  dataKey: 'y',
+  title: '流量(Gb)',
+  alias: '流量(Gb)',
+  min: 1
+}]
+
+export default {
+  name: 'Bar',
+  props: {
+    title: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      data: [],
+      scale,
+      tooltip
+    }
+  },
+  created () {
+    this.getMonthBar()
+  },
+  methods: {
+    getMonthBar () {
+      this.$http.get('/analysis/month-bar')
+        .then(res => {
+          this.data = res.result
+        })
+    }
+  }
+}
+</script>

+ 87 - 0
nginx-ui-frontend/src/components/Charts/Trend.vue

@@ -0,0 +1,87 @@
+<template>
+  <div class="chart-trend">
+    {{ term }}
+    <span>{{ rate }}%</span>
+    <span :class="['trend-icon', trend]"><a-icon :type="'caret-' + trend"/></span>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Trend',
+  props: {
+    term: {
+      type: String,
+      default: '',
+      required: true
+    },
+    percentage: {
+      type: Number,
+      default: null
+    },
+    type: {
+      type: Boolean,
+      default: null
+    },
+    target: {
+      type: Number,
+      default: 0
+    },
+    value: {
+      type: Number,
+      default: 0
+    },
+    fixed: {
+      type: Number,
+      default: 2
+    }
+  },
+  data () {
+    return {
+      trend: this.type && 'up' || 'down',
+      rate: this.percentage
+    }
+  },
+  created () {
+    const type = this.type === null ? this.value >= this.target : this.type
+    this.trend = type ? 'up' : 'down'
+    this.rate = Math.abs(this.percentage)
+  },
+  watch: {
+    percentage() {
+      this.rate = Math.abs(this.percentage)
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .chart-trend {
+    display: inline-block;
+    font-size: 14px;
+    line-height: 22px;
+
+    .trend-icon {
+      font-size: 12px;
+
+      &.up, &.down {
+        margin-left: 4px;
+        position: relative;
+        top: 1px;
+
+        i {
+          font-size: 12px;
+          transform: scale(.83);
+        }
+      }
+
+      &.up {
+        color: #f5222d;
+      }
+      &.down {
+        color: #52c41a;
+        top: -1px;
+      }
+    }
+  }
+</style>

+ 13 - 0
nginx-ui-frontend/src/components/Charts/chart.less

@@ -0,0 +1,13 @@
+.antv-chart-mini {
+  position: relative;
+  width: 100%;
+
+  .chart-wrapper {
+    position: absolute;
+    bottom: -28px;
+    width: 100%;
+
+/*    margin: 0 -5px;
+    overflow: hidden;*/
+  }
+}

+ 28 - 0
nginx-ui-frontend/src/components/Charts/index.js

@@ -0,0 +1,28 @@
+import Bar from './Bar'
+import ChartCard from './ChartCard'
+import Liquid from './Liquid'
+import MiniArea from './MiniArea'
+import MiniBar from './MiniBar'
+import MiniProgress from './MiniProgress'
+import MiniSelect from 'ant-design-vue/lib/pagination/MiniSelect'
+import MiniSmoothArea from './MiniSmoothArea'
+import Radar from './Radar'
+import RankList from './RankList'
+import TransferBar from './TransferBar'
+import Trend from './Trend'
+
+
+export {
+  Bar,
+  ChartCard,
+  Liquid,
+  MiniSmoothArea,
+  MiniSelect,
+  MiniProgress,
+  MiniArea,
+  MiniBar,
+  Radar,
+  RankList,
+  TransferBar,
+  Trend
+}

+ 4 - 0
nginx-ui-frontend/src/components/Charts/smooth.area.less

@@ -0,0 +1,4 @@
+.ant-pro-smooth-area {
+    position: relative;
+    width: 100%;
+}

+ 3 - 3
nginx-ui-frontend/src/router/index.js

@@ -11,15 +11,15 @@ export const routes = [
         component: () => import('@/layouts/BaseLayout'),
         redirect: '/domain',
         children: [
-            /*{
+            {
                 path: 'dashboard',
-                //component: () => import('@/views/dashboard/DashBoard'),
+                component: () => import('@/views/DashBoard'),
                 name: '仪表盘',
                 meta: {
                     //hiddenHeaderContent: true,
                     icon: 'home'
                 }
-            },*/
+            },
             {
                 path: 'domain',
                 name: '网站管理',

+ 12 - 1
nginx-ui-frontend/src/views/ConfigEdit.vue

@@ -1,6 +1,6 @@
 <template>
     <a-card title="配置文件实时编辑">
-        <a-textarea v-model="configText" :rows="36"/>
+        <a-textarea v-model="configText" :rows="36" @keydown.tab.prevent="pressTab"/>
         <footer-tool-bar>
             <a-button type="primary" @click="save">保存</a-button>
         </footer-tool-bar>
@@ -53,6 +53,17 @@ export default {
                 console.log(r)
                 this.$message.error("保存错误")
             })
+        },
+        pressTab(event) {
+            let target = event.target
+            let value = target.value
+            let start = target.selectionStart;
+            let end = target.selectionEnd;
+            if (event) {
+                value = value.substring(0, start) + '\t' + value.substring(end);
+                event.target.value = value;
+                setTimeout(() => target.selectionStart = target.selectionEnd = start + 1, 0);
+            }
         }
     }
 }

+ 130 - 0
nginx-ui-frontend/src/views/DashBoard.vue

@@ -0,0 +1,130 @@
+<template>
+    <div>
+        <a-row class="row-two">
+            <a-col :lg="24" :sm="24">
+                <a-card style="min-height: 250px" title="后端服务器实时数据">
+                    <a-row>
+                        <a-col :lg="12" :sm="24" class="chart">
+                            <a-statistic :value="cpu" style="margin: 0 50px 10px 0" title="CPU">
+                                <template v-slot:suffix>
+                                    <span>%</span>
+                                </template>
+                            </a-statistic>
+                            <mini-smooth-area :data-source="cpu_analytic"/>
+                        </a-col>
+                        <a-col :lg="6" :sm="10" class="chart">
+                            <span>实际内存占用</span>
+                            <div>
+                                <a-tooltip
+                                    :title="'已使用: '+ memory_used + ' / 总共: ' + memory_total">
+                                    <a-progress :percent="memory_pressure" strokeColor="rgb(135, 208, 104)" type="circle"/>
+                                </a-tooltip>
+                            </div>
+                        </a-col>
+                        <a-col :lg="6" :sm="10" class="chart">
+                            <span>存储空间</span>
+                            <div>
+                                <a-tooltip
+                                    :title="'已使用: '+ disk_used + ' / 总共: ' + disk_total">
+                                    <a-progress :percent="disk_percentage" type="circle"/>
+                                </a-tooltip>
+                            </div>
+                        </a-col>
+                    </a-row>
+                </a-card>
+            </a-col>
+        </a-row>
+    </div>
+</template>
+
+<script>
+import MiniSmoothArea from '@/components/Charts/MiniSmoothArea'
+import Vue from 'vue'
+import Viser from 'viser-vue'
+
+Vue.use(Viser)
+
+export default {
+    name: "DashBoard",
+    components: {
+        MiniSmoothArea
+    },
+    data() {
+        return {
+            websocket: null,
+            loading: true,
+            stat: {},
+            memory_pressure: 0,
+            memory_used: "",
+            memory_total: "",
+            cpu_analytic: [],
+            cpu: 0,
+            disk_percentage: 0,
+            disk_total: "",
+            disk_used: "",
+        }
+    },
+    created() {
+        this.websocket = new WebSocket(process.env["VUE_APP_API_WSS_ROOT"] + "/analytic")
+        this.websocket.onmessage = this.wsOnMessage
+        this.websocket.onopen = this.wsOpen
+        this.websocket.onerror = this.wsOnError
+    },
+    destroyed() {
+        window.clearInterval(window.InitSetInterval)
+        this.websocket.close()
+    },
+    methods: {
+        wsOpen() {
+            window.InitSetInterval = setInterval(() => {
+                this.websocket.send("ping")
+            }, 1000)
+        },
+        wsOnError() {
+            this.websocket = new WebSocket(process.env["VUE_APP_API_WSS_ROOT"] + "/analytic")
+        },
+        wsOnMessage(m) {
+            const r = JSON.parse(m.data)
+            console.log(r)
+            this.cpu = r.cpu_system + r.cpu_user
+            this.cpu_analytic.push({x: new Date(), y: this.cpu})
+            if (this.cpu_analytic.length > 30) {
+                this.cpu_analytic.shift()
+            }
+            this.cpu = this.cpu.toFixed(2)
+            this.memory_pressure = r.memory_pressure
+            this.memory_used = r.memory_used
+            this.memory_total = r.memory_total
+            this.disk_percentage = r.disk_percentage
+            this.disk_used = r.disk_used
+            this.disk_total = r.disk_total
+        }
+    }
+}
+</script>
+
+<style lang="less" scoped>
+.ant-card {
+    margin: 10px;
+    @media (max-width: 512px) {
+        margin: 10px 0;
+    }
+
+    .chart-card-content, .chart-wrapper, .chart {
+        overflow: hidden;
+    }
+}
+
+.row-two {
+    .ant-card-body {
+        min-height: 255px;
+    }
+}
+
+.row-three {
+    .ant-card {
+        min-height: 377px;
+    }
+}
+</style>
+

+ 474 - 14
nginx-ui-frontend/yarn.lock

@@ -22,6 +22,106 @@
   resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-2.1.1.tgz#7b9c08dffd4f5d41db667d9dbe5e0107d0bd9a4a"
   integrity sha512-jCH+k2Vjlno4YWl6g535nHR09PwCEmTBKAG6VqF+rhkrSPRLfgpU2maagwbZPLjaHuU5Jd1DFQ2KJpQuI6uG8w==
 
+"@antv/adjust@~0.1.0":
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/@antv/adjust/-/adjust-0.1.1.tgz#e263ab0e1a1941a648842fc086cf65a7e3b75e98"
+  integrity sha512-9FaMOyBlM4AgoRL0b5o0VhEKAYkexBNUrxV8XmpHU/9NBPJONBOB/NZUlQDqxtLItrt91tCfbAuMQmF529UX2Q==
+  dependencies:
+    "@antv/util" "~1.3.1"
+
+"@antv/attr@~0.1.2":
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/@antv/attr/-/attr-0.1.2.tgz#2eeb122fcaaf851a2d8749abc7c60519d3f77e37"
+  integrity sha512-QXjP+T2I+pJQcwZx1oCA4tipG43vgeCeKcGGKahlcxb71OBAzjJZm1QbF4frKXcnOqRkxVXtCr70X9TRair3Ew==
+  dependencies:
+    "@antv/util" "~1.3.1"
+
+"@antv/component@~0.3.3":
+  version "0.3.9"
+  resolved "https://registry.yarnpkg.com/@antv/component/-/component-0.3.9.tgz#ed561c639b7738ce03ff63a866f59e251de82a17"
+  integrity sha512-Knh/Nq0S8UkTfZj4SL7XizagTfXYqjFAYIqFtOmUaKpRMgccUi7p1oA7fJdNPGktkndljy6fUmCWocEeBXRS2g==
+  dependencies:
+    "@antv/attr" "~0.1.2"
+    "@antv/g" "~3.3.5"
+    "@antv/util" "~1.3.1"
+    wolfy87-eventemitter "~5.1.0"
+
+"@antv/coord@~0.1.0":
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/@antv/coord/-/coord-0.1.0.tgz#48a80ae36d07552f96657e7f8095227c63f0c0a9"
+  integrity sha512-W1R8h3Jfb3AfMBVfCreFPMVetgEYuwHBIGn0+d3EgYXe2ckOF8XWjkpGF1fZhOMHREMr+Gt27NGiQh8yBdLUgg==
+  dependencies:
+    "@antv/util" "~1.3.1"
+
+"@antv/g2-brush@^0.0.2":
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/@antv/g2-brush/-/g2-brush-0.0.2.tgz#0b65f3ebbf82690202913d0b6759ab2900faa841"
+  integrity sha512-7O9szwem19nmEgReXhFB8kVLRaz8J5MHvrzDSDY36YaBOaHSWRGHnvYt2KkkPqgWtHtLY1srssk4X/UmP5govA==
+
+"@antv/g2-plugin-slider@^2.1.0":
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/@antv/g2-plugin-slider/-/g2-plugin-slider-2.1.1.tgz#c20c5f1cf085bea478f8ab1fc84837e45c46a065"
+  integrity sha512-nB678VEGG3FkrvkDDFADAKjLQIeXzITEYqey5oeOpbf0vT5jOa55lQDyJDZ79cK8PmU/Hz6VPeSb3CNQBA+/FQ==
+
+"@antv/g2@~3.5.3":
+  version "3.5.17"
+  resolved "https://registry.yarnpkg.com/@antv/g2/-/g2-3.5.17.tgz#02c8bac610d21d28b4e23600bc76c48e7f59c919"
+  integrity sha512-gOjfA6pwXYEC5mrLbvg1kA3jZI5J5T2kQeGse+iBBsNc1Vje7zs9G+BleUaI4MLXSnqwhsj/ohfkP7d+h4ArNg==
+  dependencies:
+    "@antv/adjust" "~0.1.0"
+    "@antv/attr" "~0.1.2"
+    "@antv/component" "~0.3.3"
+    "@antv/coord" "~0.1.0"
+    "@antv/g" "~3.4.10"
+    "@antv/scale" "~0.1.1"
+    "@antv/util" "~1.3.1"
+    venn.js "~0.2.20"
+    wolfy87-eventemitter "~5.1.0"
+
+"@antv/g@~3.3.5":
+  version "3.3.6"
+  resolved "https://registry.yarnpkg.com/@antv/g/-/g-3.3.6.tgz#11fed9ddc9ed4e5a2aa244b7c8abb982a003f201"
+  integrity sha512-2GtyTz++s0BbN6s0ZL2/nrqGYCkd52pVoNH92YkrTdTOvpO6Z4DNoo6jGVgZdPX6Nzwli6yduC8MinVAhE8X6g==
+  dependencies:
+    "@antv/gl-matrix" "~2.7.1"
+    "@antv/util" "~1.3.1"
+    d3-ease "~1.0.3"
+    d3-interpolate "~1.1.5"
+    d3-timer "~1.0.6"
+    wolfy87-eventemitter "~5.1.0"
+
+"@antv/g@~3.4.10":
+  version "3.4.10"
+  resolved "https://registry.yarnpkg.com/@antv/g/-/g-3.4.10.tgz#e7b616aa21b17ac51850d033332a5af8de8fe015"
+  integrity sha512-pKy/L1SyRBsXuujdkggqrdBA0/ciAgHiArYBdIJsxHRxCneUP01wGwHdGfDayh2+S0gcSBHynjhoEahsaZaLkw==
+  dependencies:
+    "@antv/gl-matrix" "~2.7.1"
+    "@antv/util" "~1.3.1"
+    d3-ease "~1.0.3"
+    d3-interpolate "~1.1.5"
+    d3-timer "~1.0.6"
+    detect-browser "^5.1.0"
+
+"@antv/gl-matrix@^2.7.1", "@antv/gl-matrix@~2.7.1":
+  version "2.7.1"
+  resolved "https://registry.yarnpkg.com/@antv/gl-matrix/-/gl-matrix-2.7.1.tgz#acb8e37f7ab3df01345aba4372d7942be42eba14"
+  integrity sha512-oOWcVNlpELIKi9x+Mm1Vwbz8pXfkbJKykoCIOJ/dNK79hSIANbpXJ5d3Rra9/wZqK6MC961B7sybFhPlLraT3Q==
+
+"@antv/scale@~0.1.1":
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/@antv/scale/-/scale-0.1.5.tgz#243266e8b9047cf64b2fdfc40f9834cf0846496e"
+  integrity sha512-7RAu4iH5+Hk21h6+aBMiDTfmLf4IibK2SWjx/+E4f4AXRpqucO+8u7IbZdFkakAWxvqhJtN3oePJuTKqOMcmlg==
+  dependencies:
+    "@antv/util" "~1.3.1"
+    fecha "~2.3.3"
+
+"@antv/util@~1.3.1":
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/@antv/util/-/util-1.3.1.tgz#30a34b201ff9126ec0d58c72c8166a9c3e644ccd"
+  integrity sha512-cbUta0hIJrKEaW3eKoGarz3Ita+9qUPF2YzTj8A6wds/nNiy20G26ztIWHU+5ThLc13B1n5Ik52LbaCaeg9enA==
+  dependencies:
+    "@antv/gl-matrix" "^2.7.1"
+
 "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13":
   version "7.12.13"
   resolved "https://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.12.13.tgz?cache=0&sync_timestamp=1612314620252&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658"
@@ -984,6 +1084,11 @@
   dependencies:
     "@types/node" "*"
 
+"@types/d3-format@*":
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/@types/d3-format/-/d3-format-2.0.0.tgz#607d261cb268f0a027f100575491031539a40ee6"
+  integrity sha512-uagdkftxnGkO4pZw5jEYOM5ZnZOEsh7z8j11Qxk85UkB2RzfUUxRl7R9VvvJZHwKn8l+x+rpS77Nusq7FkFmIg==
+
 "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.18":
   version "4.17.18"
   resolved "https://registry.npm.taobao.org/@types/express-serve-static-core/download/@types/express-serve-static-core-4.17.18.tgz?cache=0&sync_timestamp=1613378403459&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fexpress-serve-static-core%2Fdownload%2F%40types%2Fexpress-serve-static-core-4.17.18.tgz#8371e260f40e0e1ca0c116a9afcd9426fa094c40"
@@ -1023,6 +1128,11 @@
   resolved "https://registry.npm.taobao.org/@types/json-schema/download/@types/json-schema-7.0.7.tgz?cache=0&sync_timestamp=1613378919536&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fjson-schema%2Fdownload%2F%40types%2Fjson-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
   integrity sha1-mKmTUWyFnrDVxMjwmDF6nqaNua0=
 
+"@types/lodash@*":
+  version "4.14.168"
+  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.168.tgz#fe24632e79b7ade3f132891afff86caa5e5ce008"
+  integrity sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==
+
 "@types/mime@^1":
   version "1.3.2"
   resolved "https://registry.npm.taobao.org/@types/mime/download/@types/mime-1.3.2.tgz?cache=0&sync_timestamp=1613379359648&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fmime%2Fdownload%2F%40types%2Fmime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a"
@@ -1043,6 +1153,11 @@
   resolved "https://registry.npm.taobao.org/@types/node/download/@types/node-14.14.32.tgz?cache=0&sync_timestamp=1615136913533&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-14.14.32.tgz#90c5c4a8d72bbbfe53033f122341343249183448"
   integrity sha1-kMXEqNcru/5TAz8SI0E0MkkYNEg=
 
+"@types/node@^8.0.53":
+  version "8.10.66"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.66.tgz#dd035d409df322acc83dff62a602f12a5783bbb3"
+  integrity sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==
+
 "@types/normalize-package-data@^2.4.0":
   version "2.4.0"
   resolved "https://registry.npm.taobao.org/@types/normalize-package-data/download/@types/normalize-package-data-2.4.0.tgz?cache=0&sync_timestamp=1613379363960&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnormalize-package-data%2Fdownload%2F%40types%2Fnormalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
@@ -1614,11 +1729,25 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4:
     json-schema-traverse "^0.4.1"
     uri-js "^4.2.2"
 
+align-text@^0.1.1, align-text@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
+  integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=
+  dependencies:
+    kind-of "^3.0.2"
+    longest "^1.0.1"
+    repeat-string "^1.5.2"
+
 alphanum-sort@^1.0.0:
   version "1.0.2"
   resolved "https://registry.npm.taobao.org/alphanum-sort/download/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
   integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=
 
+amdefine@>=0.0.4:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+  integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=
+
 ansi-colors@^3.0.0:
   version "3.2.4"
   resolved "https://registry.npm.taobao.org/ansi-colors/download/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
@@ -1656,6 +1785,11 @@ ansi-regex@^5.0.0:
   resolved "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
   integrity sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U=
 
+ansi-styles@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+  integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
+
 ansi-styles@^3.2.0, ansi-styles@^3.2.1:
   version "3.2.1"
   resolved "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.1.tgz?cache=0&sync_timestamp=1611325747047&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
@@ -2356,6 +2490,11 @@ camel-case@3.0.x:
     no-case "^2.2.0"
     upper-case "^1.1.1"
 
+camelcase@^1.0.2:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+  integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=
+
 camelcase@^5.0.0, camelcase@^5.3.1:
   version "5.3.1"
   resolved "https://registry.npm.taobao.org/camelcase/download/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
@@ -2391,6 +2530,25 @@ caseless@~0.12.0:
   resolved "https://registry.npm.taobao.org/caseless/download/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
   integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
 
+center-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
+  integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60=
+  dependencies:
+    align-text "^0.1.3"
+    lazy-cache "^1.0.3"
+
+chalk@^1.1.1:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+  integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
+  dependencies:
+    ansi-styles "^2.2.1"
+    escape-string-regexp "^1.0.2"
+    has-ansi "^2.0.0"
+    strip-ansi "^3.0.0"
+    supports-color "^2.0.0"
+
 chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2:
   version "2.4.2"
   resolved "https://registry.npm.taobao.org/chalk/download/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
@@ -2549,6 +2707,15 @@ clipboardy@^2.3.0:
     execa "^1.0.0"
     is-wsl "^2.1.1"
 
+cliui@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
+  integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=
+  dependencies:
+    center-align "^0.1.1"
+    right-align "^0.1.1"
+    wordwrap "0.0.2"
+
 cliui@^5.0.0:
   version "5.0.0"
   resolved "https://registry.npm.taobao.org/cliui/download/cliui-5.0.0.tgz?cache=0&sync_timestamp=1604880033053&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcliui%2Fdownload%2Fcliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
@@ -2761,6 +2928,11 @@ content-type@~1.0.4:
   resolved "https://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
   integrity sha1-4TjMdeBAxyexlm/l5fjJruJW/js=
 
+contour_plot@^0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/contour_plot/-/contour_plot-0.0.1.tgz#475870f032b8e338412aa5fc507880f0bf495c77"
+  integrity sha1-R1hw8DK44zhBKqX8UHiA8L9JXHc=
+
 convert-source-map@^1.7.0:
   version "1.7.0"
   resolved "https://registry.npm.taobao.org/convert-source-map/download/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
@@ -3083,6 +3255,62 @@ cyclist@^1.0.1:
   resolved "https://registry.npm.taobao.org/cyclist/download/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
   integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=
 
+d3-color@1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.1.tgz#c52002bf8846ada4424d55d97982fef26eb3bc8a"
+  integrity sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==
+
+d3-dispatch@1:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.6.tgz#00d37bcee4dd8cd97729dd893a0ac29caaba5d58"
+  integrity sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==
+
+d3-ease@1, d3-ease@~1.0.3:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.7.tgz#9a834890ef8b8ae8c558b2fe55bd57f5993b85e2"
+  integrity sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==
+
+d3-format@^1.3.0:
+  version "1.4.5"
+  resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.5.tgz#374f2ba1320e3717eb74a9356c67daee17a7edb4"
+  integrity sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==
+
+d3-interpolate@1:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.4.0.tgz#526e79e2d80daa383f9e0c1c1c7dcc0f0583e987"
+  integrity sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==
+  dependencies:
+    d3-color "1"
+
+d3-interpolate@~1.1.5:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.1.6.tgz#2cf395ae2381804df08aa1bf766b7f97b5f68fb6"
+  integrity sha512-mOnv5a+pZzkNIHtw/V6I+w9Lqm9L5bG3OTXPM5A+QO0yyVMQ4W1uZhR+VOJmazaOZXri2ppbiZ5BUNWT0pFM9A==
+  dependencies:
+    d3-color "1"
+
+d3-selection@^1.0.2, d3-selection@^1.1.0:
+  version "1.4.2"
+  resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.4.2.tgz#dcaa49522c0dbf32d6c1858afc26b6094555bc5c"
+  integrity sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==
+
+d3-timer@1, d3-timer@~1.0.6:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.10.tgz#dfe76b8a91748831b13b6d9c793ffbd508dd9de5"
+  integrity sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==
+
+d3-transition@^1.0.1:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.3.2.tgz#a98ef2151be8d8600543434c1ca80140ae23b398"
+  integrity sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==
+  dependencies:
+    d3-color "1"
+    d3-dispatch "1"
+    d3-ease "1"
+    d3-interpolate "1"
+    d3-selection "^1.1.0"
+    d3-timer "1"
+
 dashdash@^1.12.0:
   version "1.14.1"
   resolved "https://registry.npm.taobao.org/dashdash/download/dashdash-1.14.1.tgz?cache=0&sync_timestamp=1601073454623&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdashdash%2Fdownload%2Fdashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
@@ -3116,7 +3344,7 @@ debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
   dependencies:
     ms "2.1.2"
 
-decamelize@^1.2.0:
+decamelize@^1.0.0, decamelize@^1.2.0:
   version "1.2.0"
   resolved "https://registry.npm.taobao.org/decamelize/download/decamelize-1.2.0.tgz?cache=0&sync_timestamp=1610348702723&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdecamelize%2Fdownload%2Fdecamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
   integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
@@ -3126,7 +3354,7 @@ decode-uri-component@^0.2.0:
   resolved "https://registry.npm.taobao.org/decode-uri-component/download/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
   integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
 
-deep-equal@^1.0.1:
+deep-equal@^1.0.1, deep-equal@~1.1.1:
   version "1.1.1"
   resolved "https://registry.npm.taobao.org/deep-equal/download/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a"
   integrity sha1-tcmMlCzv+vfLBR4k4UNKJaLmB2o=
@@ -3204,6 +3432,11 @@ define-property@^2.0.2:
     is-descriptor "^1.0.2"
     isobject "^3.0.1"
 
+defined@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
+  integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=
+
 del@^4.1.1:
   version "4.1.1"
   resolved "https://registry.npm.taobao.org/del/download/del-4.1.1.tgz?cache=0&sync_timestamp=1612519684117&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdel%2Fdownload%2Fdel-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4"
@@ -3240,6 +3473,11 @@ destroy@~1.0.4:
   resolved "https://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
   integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
 
+detect-browser@^5.1.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.2.0.tgz#c9cd5afa96a6a19fda0bbe9e9be48a6b6e1e9c97"
+  integrity sha512-tr7XntDAu50BVENgQfajMLzacmSe34D+qZc4zjnniz0ZVuw/TZcLcyxHQjYpJTM36sGEkZZlYLnIM1hH7alTMA==
+
 detect-node@^2.0.4:
   version "2.0.4"
   resolved "https://registry.npm.taobao.org/detect-node/download/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
@@ -3372,6 +3610,13 @@ dotenv@^8.2.0:
   resolved "https://registry.npm.taobao.org/dotenv/download/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
   integrity sha1-l+YZJZradQ7qPk6j4mvO6lQksWo=
 
+dotignore@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905"
+  integrity sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==
+  dependencies:
+    minimatch "^3.0.4"
+
 duplexer@^0.1.1:
   version "0.1.2"
   resolved "https://registry.npm.taobao.org/duplexer/download/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
@@ -3546,7 +3791,7 @@ escape-html@~1.0.3:
   resolved "https://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
   integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
 
-escape-string-regexp@^1.0.5:
+escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
   version "1.0.5"
   resolved "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fescape-string-regexp%2Fdownload%2Fescape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
   integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
@@ -3898,6 +4143,11 @@ faye-websocket@^0.11.3:
   dependencies:
     websocket-driver ">=0.5.1"
 
+fecha@~2.3.3:
+  version "2.3.3"
+  resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd"
+  integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==
+
 figgy-pudding@^3.5.1:
   version "3.5.2"
   resolved "https://registry.npm.taobao.org/figgy-pudding/download/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e"
@@ -4042,11 +4292,29 @@ flush-write-stream@^1.0.0:
     inherits "^2.0.3"
     readable-stream "^2.3.6"
 
+fmin@0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/fmin/-/fmin-0.0.2.tgz#59bbb40d43ffdc1c94cd00a568c41f95f1973017"
+  integrity sha1-Wbu0DUP/3ByUzQClaMQflfGXMBc=
+  dependencies:
+    contour_plot "^0.0.1"
+    json2module "^0.0.3"
+    rollup "^0.25.8"
+    tape "^4.5.1"
+    uglify-js "^2.6.2"
+
 follow-redirects@^1.0.0, follow-redirects@^1.10.0:
   version "1.13.3"
   resolved "https://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
   integrity sha1-5VmK1QF0wbxOhyMB6CrCzZf5Amc=
 
+for-each@~0.3.3:
+  version "0.3.3"
+  resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
+  integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==
+  dependencies:
+    is-callable "^1.1.3"
+
 for-in@^1.0.2:
   version "1.0.2"
   resolved "https://registry.npm.taobao.org/for-in/download/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@@ -4135,7 +4403,7 @@ fsevents@~2.3.1:
   resolved "https://registry.npm.taobao.org/fsevents/download/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
   integrity sha1-ilJveLj99GI7cJ4Ll1xSwkwC/Ro=
 
-function-bind@^1.1.1:
+function-bind@^1.1.1, function-bind@~1.1.1:
   version "1.1.1"
   resolved "https://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
   integrity sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=
@@ -4215,7 +4483,7 @@ glob-to-regexp@^0.3.0:
   resolved "https://registry.npm.taobao.org/glob-to-regexp/download/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
   integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
 
-glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
+glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@~7.1.6:
   version "7.1.6"
   resolved "https://registry.npm.taobao.org/glob/download/glob-7.1.6.tgz?cache=0&sync_timestamp=1599054256752&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglob%2Fdownload%2Fglob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
   integrity sha1-FB8zuBp8JJLhJVlDB0gMRmeSeKY=
@@ -4307,6 +4575,13 @@ har-validator@~5.1.3:
     ajv "^6.12.3"
     har-schema "^2.0.0"
 
+has-ansi@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+  integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
+  dependencies:
+    ansi-regex "^2.0.0"
+
 has-bigints@^1.0.0:
   version "1.0.0"
   resolved "https://registry.npm.taobao.org/has-bigints/download/has-bigints-1.0.0.tgz#d9b2100824195e39a0c343c127f389d66a5e27dc"
@@ -4358,7 +4633,7 @@ has-values@^1.0.0:
     is-number "^3.0.0"
     kind-of "^4.0.0"
 
-has@^1.0.0, has@^1.0.3:
+has@^1.0.0, has@^1.0.3, has@~1.0.3:
   version "1.0.3"
   resolved "https://registry.npm.taobao.org/has/download/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
   integrity sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=
@@ -4700,7 +4975,7 @@ inflight@^1.0.4:
     once "^1.3.0"
     wrappy "1"
 
-inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3:
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4:
   version "2.0.4"
   resolved "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
   integrity sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=
@@ -4834,7 +5109,7 @@ is-buffer@^1.1.5:
   resolved "https://registry.npm.taobao.org/is-buffer/download/is-buffer-1.1.6.tgz?cache=0&sync_timestamp=1604429452232&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-buffer%2Fdownload%2Fis-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
   integrity sha1-76ouqdqg16suoTqXsritUf776L4=
 
-is-callable@^1.1.4, is-callable@^1.2.3:
+is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.3:
   version "1.2.3"
   resolved "https://registry.npm.taobao.org/is-callable/download/is-callable-1.2.3.tgz?cache=0&sync_timestamp=1612132911724&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-callable%2Fdownload%2Fis-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e"
   integrity sha1-ix4FALc6HXbHBIdjbzaOUZ3o244=
@@ -5024,6 +5299,13 @@ is-regex@^1.0.4, is-regex@^1.1.2:
     call-bind "^1.0.2"
     has-symbols "^1.0.1"
 
+is-regex@~1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae"
+  integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==
+  dependencies:
+    has "^1.0.3"
+
 is-resolvable@^1.0.0:
   version "1.1.0"
   resolved "https://registry.npm.taobao.org/is-resolvable/download/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88"
@@ -5200,6 +5482,13 @@ json-stringify-safe@~5.0.1:
   resolved "https://registry.npm.taobao.org/json-stringify-safe/download/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
   integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
 
+json2module@^0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/json2module/-/json2module-0.0.3.tgz#00fb5f4a9b7adfc3f0647c29cb17bcd1979be9b2"
+  integrity sha1-APtfSpt638PwZHwpyxe80Zeb6bI=
+  dependencies:
+    rw "^1.3.2"
+
 json2mq@^0.2.0:
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/json2mq/-/json2mq-0.2.0.tgz#b637bd3ba9eabe122c83e9720483aeb10d2c904a"
@@ -5292,6 +5581,11 @@ launch-editor@^2.2.1:
     chalk "^2.3.0"
     shell-quote "^1.6.1"
 
+lazy-cache@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+  integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4=
+
 less-loader@^5.0.0:
   version "5.0.0"
   resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-5.0.0.tgz#498dde3a6c6c4f887458ee9ed3f086a12ad1b466"
@@ -5426,7 +5720,7 @@ lodash.uniq@^4.5.0:
   resolved "https://registry.npm.taobao.org/lodash.uniq/download/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
   integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
 
-lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.3, lodash@^4.17.5:
+lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5:
   version "4.17.21"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
   integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -5443,6 +5737,11 @@ loglevel@^1.6.8:
   resolved "https://registry.npm.taobao.org/loglevel/download/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197"
   integrity sha1-AF/eL15uRwaPk1/yhXPhJe9y8Zc=
 
+longest@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
+  integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=
+
 loose-envify@^1.0.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
@@ -5658,7 +5957,7 @@ minimatch@^3.0.4:
   dependencies:
     brace-expansion "^1.1.7"
 
-minimist@^1.2.0, minimist@^1.2.5:
+minimist@^1.2.0, minimist@^1.2.5, minimist@~1.2.5:
   version "1.2.5"
   resolved "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
   integrity sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI=
@@ -6012,6 +6311,11 @@ object-inspect@^1.9.0:
   resolved "https://registry.npm.taobao.org/object-inspect/download/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a"
   integrity sha1-yQUh104RJ7ZyZt7TOUrWEWmGUzo=
 
+object-inspect@~1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67"
+  integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==
+
 object-is@^1.0.1:
   version "1.1.5"
   resolved "https://registry.npm.taobao.org/object-is/download/object-is-1.1.5.tgz?cache=0&sync_timestamp=1613857698573&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fobject-is%2Fdownload%2Fobject-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac"
@@ -7143,7 +7447,7 @@ repeat-element@^1.1.2:
   resolved "https://registry.npm.taobao.org/repeat-element/download/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
   integrity sha1-eC4NglwMWjuzlzH4Tv7mt0Lmsc4=
 
-repeat-string@^1.6.1:
+repeat-string@^1.5.2, repeat-string@^1.6.1:
   version "1.6.1"
   resolved "https://registry.npm.taobao.org/repeat-string/download/repeat-string-1.6.1.tgz?cache=0&sync_timestamp=1589682793094&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frepeat-string%2Fdownload%2Frepeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
   integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
@@ -7224,6 +7528,13 @@ resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2:
     is-core-module "^2.2.0"
     path-parse "^1.0.6"
 
+resolve@~1.17.0:
+  version "1.17.0"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
+  integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==
+  dependencies:
+    path-parse "^1.0.6"
+
 restore-cursor@^2.0.0:
   version "2.0.0"
   resolved "https://registry.npm.taobao.org/restore-cursor/download/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
@@ -7240,6 +7551,13 @@ restore-cursor@^3.1.0:
     onetime "^5.1.0"
     signal-exit "^3.0.2"
 
+resumer@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759"
+  integrity sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=
+  dependencies:
+    through "~2.3.4"
+
 ret@~0.1.10:
   version "0.1.15"
   resolved "https://registry.npm.taobao.org/ret/download/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
@@ -7260,6 +7578,13 @@ rgba-regex@^1.0.0:
   resolved "https://registry.npm.taobao.org/rgba-regex/download/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
   integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=
 
+right-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
+  integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8=
+  dependencies:
+    align-text "^0.1.1"
+
 rimraf@2.6.3:
   version "2.6.3"
   resolved "https://registry.npm.taobao.org/rimraf/download/rimraf-2.6.3.tgz?cache=0&sync_timestamp=1589682814592&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frimraf%2Fdownload%2Frimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
@@ -7282,6 +7607,15 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
     hash-base "^3.0.0"
     inherits "^2.0.1"
 
+rollup@^0.25.8:
+  version "0.25.8"
+  resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.25.8.tgz#bf6ce83b87510d163446eeaa577ed6a6fc5835e0"
+  integrity sha1-v2zoO4dRDRY0Ru6qV37WpvxYNeA=
+  dependencies:
+    chalk "^1.1.1"
+    minimist "^1.2.0"
+    source-map-support "^0.3.2"
+
 run-async@^2.4.0:
   version "2.4.1"
   resolved "https://registry.npm.taobao.org/run-async/download/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
@@ -7294,6 +7628,11 @@ run-queue@^1.0.0, run-queue@^1.0.3:
   dependencies:
     aproba "^1.1.1"
 
+rw@^1.3.2:
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
+  integrity sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=
+
 rxjs@^6.6.0:
   version "6.6.6"
   resolved "https://registry.npm.taobao.org/rxjs/download/rxjs-6.6.6.tgz?cache=0&sync_timestamp=1614458618256&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frxjs%2Fdownload%2Frxjs-6.6.6.tgz#14d8417aa5a07c5e633995b525e1e3c0dec03b70"
@@ -7604,6 +7943,13 @@ source-map-resolve@^0.5.0:
     source-map-url "^0.4.0"
     urix "^0.1.0"
 
+source-map-support@^0.3.2:
+  version "0.3.3"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.3.3.tgz#34900977d5ba3f07c7757ee72e73bb1a9b53754f"
+  integrity sha1-NJAJd9W6PwfHdX7nLnO7GptTdU8=
+  dependencies:
+    source-map "0.1.32"
+
 source-map-support@~0.5.12:
   version "0.5.19"
   resolved "https://registry.npm.taobao.org/source-map-support/download/source-map-support-0.5.19.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map-support%2Fdownload%2Fsource-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
@@ -7617,7 +7963,14 @@ source-map-url@^0.4.0:
   resolved "https://registry.npm.taobao.org/source-map-url/download/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56"
   integrity sha1-CvZmBadFpaL5HPG7+KevvCg97FY=
 
-source-map@^0.5.0, source-map@^0.5.6:
+source-map@0.1.32:
+  version "0.1.32"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266"
+  integrity sha1-yLbBZ3l7pHQKjqMyUhYv8IWRsmY=
+  dependencies:
+    amdefine ">=0.0.4"
+
+source-map@^0.5.0, source-map@^0.5.6, source-map@~0.5.1:
   version "0.5.7"
   resolved "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz?cache=0&sync_timestamp=1589682764497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map%2Fdownload%2Fsource-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
   integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
@@ -7814,6 +8167,15 @@ string-width@^4.1.0, string-width@^4.2.0:
     is-fullwidth-code-point "^3.0.0"
     strip-ansi "^6.0.0"
 
+string.prototype.trim@~1.2.1:
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.4.tgz#6014689baf5efaf106ad031a5fa45157666ed1bd"
+  integrity sha512-hWCk/iqf7lp0/AgTF7/ddO1IWtSNPASjlzCicV5irAVdE1grjsneK26YG6xACMBEdCvO8fUST0UzDMh/2Qy+9Q==
+  dependencies:
+    call-bind "^1.0.2"
+    define-properties "^1.1.3"
+    es-abstract "^1.18.0-next.2"
+
 string.prototype.trimend@^1.0.4:
   version "1.0.4"
   resolved "https://registry.npm.taobao.org/string.prototype.trimend/download/string.prototype.trimend-1.0.4.tgz?cache=0&sync_timestamp=1614127461586&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstring.prototype.trimend%2Fdownload%2Fstring.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80"
@@ -7901,6 +8263,11 @@ stylehacks@^4.0.0:
     postcss "^7.0.0"
     postcss-selector-parser "^3.0.0"
 
+supports-color@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+  integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
+
 supports-color@^5.3.0:
   version "5.5.0"
   resolved "https://registry.npm.taobao.org/supports-color/download/supports-color-5.5.0.tgz?cache=0&sync_timestamp=1611394878204&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@@ -7961,6 +8328,27 @@ tapable@^1.0.0, tapable@^1.1.3:
   resolved "https://registry.npm.taobao.org/tapable/download/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
   integrity sha1-ofzMBrWNth/XpF2i2kT186Pme6I=
 
+tape@^4.5.1:
+  version "4.13.3"
+  resolved "https://registry.yarnpkg.com/tape/-/tape-4.13.3.tgz#51b3d91c83668c7a45b1a594b607dee0a0b46278"
+  integrity sha512-0/Y20PwRIUkQcTCSi4AASs+OANZZwqPKaipGCEwp10dQMipVvSZwUUCi01Y/OklIGyHKFhIcjock+DKnBfLAFw==
+  dependencies:
+    deep-equal "~1.1.1"
+    defined "~1.0.0"
+    dotignore "~0.1.2"
+    for-each "~0.3.3"
+    function-bind "~1.1.1"
+    glob "~7.1.6"
+    has "~1.0.3"
+    inherits "~2.0.4"
+    is-regex "~1.0.5"
+    minimist "~1.2.5"
+    object-inspect "~1.7.0"
+    resolve "~1.17.0"
+    resumer "~0.0.0"
+    string.prototype.trim "~1.2.1"
+    through "~2.3.8"
+
 terser-webpack-plugin@^1.4.3:
   version "1.4.5"
   resolved "https://registry.npm.taobao.org/terser-webpack-plugin/download/terser-webpack-plugin-1.4.5.tgz?cache=0&sync_timestamp=1610196021147&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fterser-webpack-plugin%2Fdownload%2Fterser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b"
@@ -8036,7 +8424,7 @@ through2@^2.0.0:
     readable-stream "~2.3.6"
     xtend "~4.0.1"
 
-through@^2.3.6:
+through@^2.3.6, through@~2.3.4, through@~2.3.8:
   version "2.3.8"
   resolved "https://registry.npm.taobao.org/through/download/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
   integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
@@ -8205,6 +8593,21 @@ uglify-js@3.4.x:
     commander "~2.19.0"
     source-map "~0.6.1"
 
+uglify-js@^2.6.2:
+  version "2.8.29"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
+  integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0=
+  dependencies:
+    source-map "~0.5.1"
+    yargs "~3.10.0"
+  optionalDependencies:
+    uglify-to-browserify "~1.0.0"
+
+uglify-to-browserify@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+  integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc=
+
 unbox-primitive@^1.0.0:
   version "1.0.0"
   resolved "https://registry.npm.taobao.org/unbox-primitive/download/unbox-primitive-1.0.0.tgz#eeacbc4affa28e9b3d36b5eaeccc50b3251b1d3f"
@@ -8422,6 +8825,15 @@ vendors@^1.0.0:
   resolved "https://registry.npm.taobao.org/vendors/download/vendors-1.0.4.tgz?cache=0&sync_timestamp=1615203486079&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvendors%2Fdownload%2Fvendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e"
   integrity sha1-4rgApT56Kbk1BsPPQRANFsTErY4=
 
+venn.js@~0.2.20:
+  version "0.2.20"
+  resolved "https://registry.yarnpkg.com/venn.js/-/venn.js-0.2.20.tgz#3f0e50cc75cba1f58692a8a32f67bd7aaf1aa6fa"
+  integrity sha512-bb5SYq/wamY9fvcuErb9a0FJkgIFHJjkLZWonQ+DoKKuDX3WPH2B4ouI1ce4K2iejBklQy6r1ly8nOGIyOCO6w==
+  dependencies:
+    d3-selection "^1.0.2"
+    d3-transition "^1.0.1"
+    fmin "0.0.2"
+
 verror@1.10.0:
   version "1.10.0"
   resolved "https://registry.npm.taobao.org/verror/download/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
@@ -8431,6 +8843,29 @@ verror@1.10.0:
     core-util-is "1.0.2"
     extsprintf "^1.2.0"
 
+viser-vue@^2.4.8:
+  version "2.4.8"
+  resolved "https://registry.yarnpkg.com/viser-vue/-/viser-vue-2.4.8.tgz#3fdb058445cba59c1ccee9cc9c2024bec29926d4"
+  integrity sha512-ERAREN+6k/ywrwT+swcMo4CDIAq6dBjnB0+lhmsSfaip06BGHSBfNKg6yl7/4GJ9Nk2kioUw3llNhEboJuIKmQ==
+  dependencies:
+    "@types/node" "*"
+    viser "^2.0.0"
+    vue "^2.5.3"
+
+viser@^2.0.0:
+  version "2.4.9"
+  resolved "https://registry.yarnpkg.com/viser/-/viser-2.4.9.tgz#57f4c70f5702fb80e38843f29025cea575cbc60a"
+  integrity sha512-DKsqtMa3TZYQHEZ7jp4kpNp1Iqomda7d+3IkkIjIdKQvfL8OeksXfy/ECZUY1hTrGoOe7cq85+6PMS+MPn4mgQ==
+  dependencies:
+    "@antv/g2" "~3.5.3"
+    "@antv/g2-brush" "^0.0.2"
+    "@antv/g2-plugin-slider" "^2.1.0"
+    "@types/d3-format" "*"
+    "@types/lodash" "*"
+    "@types/node" "^8.0.53"
+    d3-format "^1.3.0"
+    lodash "^4.17.4"
+
 vm-browserify@^1.0.1:
   version "1.1.2"
   resolved "https://registry.npm.taobao.org/vm-browserify/download/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
@@ -8514,7 +8949,7 @@ vue-template-es2015-compiler@^1.9.0:
   resolved "https://registry.npm.taobao.org/vue-template-es2015-compiler/download/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
   integrity sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=
 
-vue@^2.6.11:
+vue@^2.5.3, vue@^2.6.11:
   version "2.6.12"
   resolved "https://registry.npm.taobao.org/vue/download/vue-2.6.12.tgz?cache=0&sync_timestamp=1614614707443&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue%2Fdownload%2Fvue-2.6.12.tgz#f5ebd4fa6bd2869403e29a896aed4904456c9123"
   integrity sha1-9evU+mvShpQD4pqJau1JBEVskSM=
@@ -8744,11 +9179,26 @@ which@^2.0.1:
   dependencies:
     isexe "^2.0.0"
 
+window-size@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+  integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=
+
+wolfy87-eventemitter@~5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/wolfy87-eventemitter/-/wolfy87-eventemitter-5.1.0.tgz#35c1ac0dd1ac0c15e35d981508fc22084a13a011"
+  integrity sha1-NcGsDdGsDBXjXZgVCPwiCEoToBE=
+
 word-wrap@~1.2.3:
   version "1.2.3"
   resolved "https://registry.npm.taobao.org/word-wrap/download/word-wrap-1.2.3.tgz?cache=0&sync_timestamp=1589683603678&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fword-wrap%2Fdownload%2Fword-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
   integrity sha1-YQY29rH3A4kb00dxzLF/uTtHB5w=
 
+wordwrap@0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
+  integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=
+
 worker-farm@^1.7.0:
   version "1.7.0"
   resolved "https://registry.npm.taobao.org/worker-farm/download/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8"
@@ -8874,6 +9324,16 @@ yargs@^16.0.0:
     y18n "^5.0.5"
     yargs-parser "^20.2.2"
 
+yargs@~3.10.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
+  integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=
+  dependencies:
+    camelcase "^1.0.2"
+    cliui "^2.1.0"
+    decamelize "^1.0.0"
+    window-size "0.1.0"
+
 yorkie@^2.0.0:
   version "2.0.0"
   resolved "https://registry.npm.taobao.org/yorkie/download/yorkie-2.0.0.tgz#92411912d435214e12c51c2ae1093e54b6bb83d9"

+ 10 - 9
server/api/analytic.go

@@ -45,10 +45,12 @@ func Analytic(c *gin.Context) {
                 return
             }
             response["memory_total"] = humanize.Bytes(memoryStat.Total)
-            response["memory_used"] = humanize.Bytes(memoryStat.Total)
+            response["memory_used"] = humanize.Bytes(memoryStat.Used)
             response["memory_cached"] = humanize.Bytes(memoryStat.Cached)
             response["memory_free"] = humanize.Bytes(memoryStat.Free)
 
+            response["memory_pressure"] = memoryStat.Used * 100 / memoryStat.Total
+
             before, err := cpu.Get()
             if err != nil {
                 fmt.Println(err)
@@ -61,19 +63,18 @@ func Analytic(c *gin.Context) {
 
             total := float64(after.Total - before.Total)
 
-            response["cpu_user"] = strconv.FormatFloat(
-                float64(after.User-before.User)/total*100,
-                'f', 2, 64)
+            response["cpu_user"], _ = strconv.ParseFloat(fmt.Sprintf("%.2f",
+                float64(after.User-before.User)/total*100), 64)
 
-            response["cpu_system"] = strconv.FormatFloat(float64(after.System-before.System)/total*100,
-                'f', 2, 64)
+            response["cpu_system"], _ = strconv.ParseFloat(fmt.Sprintf("%.2f",
+                float64(after.System-before.System)/total*100), 64)
 
-            response["cpu_idle"] = strconv.FormatFloat(float64(after.Idle-before.Idle)/total*100,
-                'f', 2, 64)
+            response["cpu_idle"], _ = strconv.ParseFloat(fmt.Sprintf("%.2f",
+                float64(after.Idle-before.Idle)/total*100), 64)
 
             used, _total, percentage, err := tool.DiskUsage(".")
 
-            response["disk_userd"] = used
+            response["disk_used"] = used
             response["disk_total"] = _total
             response["disk_percentage"] = percentage
 

+ 3 - 6
server/router/routers.go

@@ -1,10 +1,9 @@
 package router
 
 import (
-	"github.com/0xJacky/Nginx-UI/api"
-	"github.com/gin-gonic/gin"
-	"net/http"
-    "github.com/gin-contrib/cors"
+    "github.com/0xJacky/Nginx-UI/api"
+    "github.com/gin-gonic/gin"
+    "net/http"
 )
 
 func InitRouter() *gin.Engine {
@@ -13,8 +12,6 @@ func InitRouter() *gin.Engine {
 
 	r.Use(gin.Recovery())
 
-    r.Use(cors.Default())
-
 	r.GET("/", func(c *gin.Context) {
 		c.JSON(http.StatusOK, gin.H{
 			"message": "Hello World",

+ 5 - 3
server/tool/analytic.go

@@ -7,10 +7,10 @@ import (
     "strconv"
 )
 
-func DiskUsage(path string) (string, string, string, error) {
+func DiskUsage(path string) (string, string, float64, error) {
     di, err := disk.GetInfo(path)
     if err != nil {
-        return "", "", "", err
+        return "", "", 0, err
     }
     percentage := (float64(di.Total-di.Free) / float64(di.Total)) * 100
     fmt.Printf("%s of %s disk space used (%0.2f%%)\n",
@@ -18,6 +18,8 @@ func DiskUsage(path string) (string, string, string, error) {
         humanize.Bytes(di.Total),
         percentage,
     )
+    percentage, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", percentage), 64)
+
     return humanize.Bytes(di.Total-di.Free), humanize.Bytes(di.Total),
-        strconv.FormatFloat(percentage, 'f', 2, 64), nil
+        percentage, nil
 }