Feat: Convert from unix timestamp to custom time format (#336)

diff --git a/src/store/modules/dashboard/dashboard-option.ts b/src/store/modules/dashboard/dashboard-option.ts
index 960a3b8..d3ae4de 100644
--- a/src/store/modules/dashboard/dashboard-option.ts
+++ b/src/store/modules/dashboard/dashboard-option.ts
@@ -59,7 +59,7 @@
   },
 
   [types.UPDATE_DASHBOARD](state: State) {
-    state.updateDashboard = { _: +new Date() };
+    state.updateDashboard = { key: +new Date() };
   },
 
   [types.SET_ENDPOINTS](state: State, data: any) {
@@ -119,6 +119,10 @@
       });
   },
   GET_SERVICE_ENDPOINTS(context: { commit: Commit; state: any }, params: { keyword: string }) {
+    if (!context.state.currentService.key) {
+      context.commit(types.SET_ENDPOINTS, []);
+      return;
+    }
     if (!params.keyword) {
       params.keyword = '';
     }
@@ -138,6 +142,10 @@
       });
   },
   GET_SERVICE_INSTANCES(context: { commit: Commit; state: any }, params: any) {
+    if (!context.state.currentService.key) {
+      context.commit(types.SET_INSTANCES, []);
+      return;
+    }
     return graph
       .query('queryInstances')
       .params({ serviceId: context.state.currentService.key || '', ...params })
diff --git a/src/views/components/dashboard/charts/chart-edit.vue b/src/views/components/dashboard/charts/chart-edit.vue
index 351059e..009904e 100755
--- a/src/views/components/dashboard/charts/chart-edit.vue
+++ b/src/views/components/dashboard/charts/chart-edit.vue
@@ -209,7 +209,7 @@
           <option v-for="type in CalculationType" :value="type.value" :key="type.value">{{ type.label }}</option>
         </select>
         <input
-          type="number"
+          type="text"
           class="rk-chart-edit-input long"
           :value="itemConfig.aggregationNum"
           @change="setItemConfig({ type: 'aggregationNum', value: $event.target.value })"
@@ -418,6 +418,21 @@
 
         return;
       }
+      if (params.type === 'aggregation' && ['milliseconds', 'seconds'].includes(this.itemConfig.aggregation)) {
+        const values = {
+          aggregationNum: 'YYYY-MM-DD HH:mm:ss',
+          [params.type]: params.value,
+        };
+        this.itemConfig = {
+          ...this.itemConfig,
+          ...values,
+        };
+        this.EDIT_COMP_CONFIG({
+          index: this.index,
+          values,
+        });
+        return;
+      }
       if (this.type === this.pageTypes[0]) {
         this.EDIT_TOPO_ENDPOINT_CONFIG({
           index: this.index,
diff --git a/src/views/components/dashboard/charts/chart-heatmap.vue b/src/views/components/dashboard/charts/chart-heatmap.vue
index 867d205..f736695 100644
--- a/src/views/components/dashboard/charts/chart-heatmap.vue
+++ b/src/views/components/dashboard/charts/chart-heatmap.vue
@@ -21,7 +21,6 @@
   import Vue from 'vue';
   import { Component, Prop } from 'vue-property-decorator';
   import 'echarts/lib/component/visualMap';
-  import moment from 'dayjs';
   @Component
   export default class ChartHeatmap extends Vue {
     @Prop() private title!: string;
diff --git a/src/views/components/dashboard/charts/chart-instance.vue b/src/views/components/dashboard/charts/chart-instance.vue
index fdc9801..de40e7b 100755
--- a/src/views/components/dashboard/charts/chart-instance.vue
+++ b/src/views/components/dashboard/charts/chart-instance.vue
@@ -32,7 +32,6 @@
 <script lang="ts">
   import Vue from 'vue';
   import { Component, Prop } from 'vue-property-decorator';
-  import moment from 'dayjs';
   import { State } from 'vuex-class';
   @Component
   export default class ChartInstance extends Vue {
diff --git a/src/views/components/dashboard/charts/chart-num.vue b/src/views/components/dashboard/charts/chart-num.vue
index 41d64ed..017203d 100644
--- a/src/views/components/dashboard/charts/chart-num.vue
+++ b/src/views/components/dashboard/charts/chart-num.vue
@@ -15,7 +15,9 @@
 
 <template>
   <div class="rk-chart-num b">
-    <span>{{ isNaN(data.avgNum) ? null : data.avgNum.toFixed(2) }}</span>
+    <span>{{
+      typeof data.avgNum === 'string' ? data.avgNum : isNaN(data.avgNum) ? null : data.avgNum.toFixed(2)
+    }}</span>
   </div>
 </template>
 <script lang="ts">
diff --git a/src/views/components/dashboard/charts/constant.ts b/src/views/components/dashboard/charts/constant.ts
index 91c79e3..0432e3a 100644
--- a/src/views/components/dashboard/charts/constant.ts
+++ b/src/views/components/dashboard/charts/constant.ts
@@ -37,7 +37,7 @@
 
 export const QueryMetricTypes: { [key: string]: Array<{ label: string; value: string }> } = {
   REGULAR_VALUE: [
-    { label: 'read avg value in the duration', value: 'readMetricsValue' },
+    { label: 'read the single value in the duration', value: 'readMetricsValue' },
     { label: 'read all values in the duration', value: 'readMetricsValues' },
     { label: 'get sorted top N values', value: 'sortMetrics' },
   ],
@@ -60,6 +60,8 @@
   { label: 'Minus', value: '-' },
   { label: 'Multiplication', value: '*' },
   { label: 'Division', value: '/' },
+  { label: 'Convert Unix Timestamp(milliseconds)', value: 'milliseconds' },
+  { label: 'Convert Unix Timestamp(seconds)', value: 'seconds' },
 ];
 
 export const ChartTypeOptions = [
diff --git a/src/views/components/dashboard/dashboard-item.vue b/src/views/components/dashboard/dashboard-item.vue
index fa26e41..8607437 100644
--- a/src/views/components/dashboard/dashboard-item.vue
+++ b/src/views/components/dashboard/dashboard-item.vue
@@ -63,14 +63,15 @@
 </template>
 <script lang="ts">
   import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
+  import { Mutation, State, Getter, Action } from 'vuex-class';
   import charts from './charts';
+  import dayjs from 'dayjs';
+
   import { QueryTypes } from './constant';
   import { TopologyType, ObjectsType } from '../../constant';
   import { MetricsType, CalculationType } from './charts/constant';
   import { uuid } from '@/utils/uuid.ts';
 
-  import { Mutation, State, Getter, Action } from 'vuex-class';
-
   @Component({
     components: { ...charts },
   })
@@ -150,7 +151,9 @@
 
         if (queryMetricType === QueryTypes.ReadMetricsValue) {
           this.chartSource = {
-            avgNum: this.aggregationValue({ data: resVal, type: aggregation, aggregationNum: Number(aggregationNum) }),
+            avgNum: [CalculationType[4].value, CalculationType[5].value].includes(aggregation)
+              ? this.formatDate({ data: resVal, type: aggregation, aggregationNum })
+              : this.aggregationValue({ data: resVal, type: aggregation, aggregationNum: Number(aggregationNum) }),
           };
         }
         if (queryMetricType === QueryTypes.ReadMetricsValues) {
@@ -222,6 +225,20 @@
       this.dialogConfigVisible = true;
     }
 
+    private formatDate(json: { data: number; type: string; aggregationNum: string }) {
+      let { aggregationNum } = json;
+      if (!aggregationNum) {
+        aggregationNum = 'YYYY-MM-DD HH:mm:ss';
+      }
+      if (json.type === CalculationType[4].value) {
+        return dayjs(json.data).format(aggregationNum);
+      } else if (json.type === CalculationType[5].value) {
+        return dayjs.unix(json.data).format(aggregationNum);
+      } else {
+        return json.data;
+      }
+    }
+
     private aggregationValue(json: { data: number; type: string; aggregationNum: number }) {
       if (isNaN(json.aggregationNum)) {
         return json.data;