Commit 32f333ea72b0041c975c024828c62dbb1dd60e48

Authored by fengtao
Committed by xp.Huang
1 parent 14446abd

perf: 优化接口调用历史折线图显示

... ... @@ -3,6 +3,7 @@ import { findDictItemByCode } from '/@/api/system/dict';
3 3 import { FormSchema } from '/@/components/Form';
4 4 import { DictEnum } from '/@/enums/dictEnum';
5 5 import { useI18n } from '/@/hooks/web/useI18n';
  6 +import HelpMessage from '../HelpMessage.vue';
6 7
7 8 export enum FormFieldsEnum {
8 9 NAME = 'name',
... ... @@ -62,23 +63,9 @@ export const formSchema: FormSchema[] = [
62 63 },
63 64 {
64 65 field: FormFieldsEnum.INTERFACE_ADDRESS,
65   - label: t('application.api.text.interfaceAddress'),
  66 + label: h(HelpMessage) as unknown as string,
66 67 component: 'Input',
67 68 required: true,
68   - helpMessage: [
69   - h(
70   - 'span',
71   - {
72   - style: {
73   - cursor: 'pointer',
74   - },
75   - onClick: () => {
76   - window.open('https://yunteng.yuque.com/avshoi/open_api');
77   - },
78   - },
79   - t('common.documentUrl')
80   - ) as any as string,
81   - ],
82 69 componentProps: {
83 70 maxLength: 255,
84 71 placeholder: t('application.api.search.interfaceAddressPlaceholder'),
... ...
  1 +<script lang="ts" setup>
  2 + import { BasicHelp } from '/@/components/Basic';
  3 + import { useI18n } from '/@/hooks/web/useI18n';
  4 +
  5 + function handleLinkOpenApiDoc() {
  6 + window.open('https://yunteng.yuque.com/avshoi/open_api');
  7 + }
  8 +
  9 + const { t } = useI18n();
  10 +</script>
  11 +
  12 +<template>
  13 + <div>{{ t('application.api.text.interfaceAddress') }}</div>
  14 +
  15 + <BasicHelp
  16 + placement="top"
  17 + @click="handleLinkOpenApiDoc"
  18 + class="mx-1"
  19 + :text="t('common.documentUrl')"
  20 + />
  21 +</template>
... ...
1   -<script setup lang="ts">
2   - import { Descriptions, Progress, Skeleton, Tooltip, DescriptionsItem } from 'ant-design-vue';
3   -
4   - defineProps({
5   - seriesData: {
6   - type: Array as PropType<Recordable[]>,
7   - default: () => [],
8   - },
9   - });
10   -</script>
11   -<template>
12   - <div class="m-16">
13   - <Skeleton active :paragraph="{ rows: 10 }" :loading="!seriesData">
14   - <Descriptions :column="1">
15   - <template v-for="(item, index) in seriesData" :key="item.label">
16   - <DescriptionsItem>
17   - <span
18   - class="mr-2 item-span"
19   - :style="{
20   - color:
21   - index === 0
22   - ? '#f0a16e'
23   - : index === 1
24   - ? '#868585'
25   - : index === 2
26   - ? '#e78739'
27   - : '#4e84f5',
28   - backgroundColor:
29   - index === 0 ? '#FAD672' : index === 1 ? '#CBCAC9' : index === 2 ? '#F1B889' : '',
30   - borderColor:
31   - index === 0
32   - ? '#fdee7d'
33   - : index === 1
34   - ? '#e6e6e5'
35   - : index === 2
36   - ? '#f8c296'
37   - : '#0b55f1',
38   - }"
39   - >{{ index + 1 }}</span
40   - >
41   - <div class="flex justify-between" style="width: 100%">
42   - <div class="label-span">
43   - <Tooltip :title="item.label">
44   - {{ item.label }}
45   - </Tooltip>
46   - </div>
47   - <div class="flex w-7/10">
48   - <Progress
49   - :showInfo="false"
50   - size="small"
51   - style="width: 70%"
52   - :percent="(item.value / seriesData[0].value) * 100"
53   - :strokeWidth="12"
54   - :strokeColor="
55   - index === 0
56   - ? '#ea5b42'
57   - : index === 1
58   - ? '#666'
59   - : index === 2
60   - ? '#e4751a'
61   - : '#b5b6b6'
62   - "
63   - />
64   - <span
65   - class="ml-2"
66   - :style="{ color: index === 0 ? '#EA5B42' : index === 2 ? '#E4751A' : '#666' }"
67   - >
68   - {{ item.value }}
69   - </span>
70   - </div>
71   - </div>
72   - </DescriptionsItem>
73   - </template>
74   - </Descriptions>
75   - </Skeleton>
76   - </div>
77   -</template>
78   -
79   -<style scoped lang="less">
80   - .item-span {
81   - width: 1.4rem;
82   - height: 1.25rem;
83   - border: 1px solid;
84   - color: #0b55f1;
85   - border-radius: 50%;
86   - display: flex;
87   - align-items: center;
88   - justify-content: center;
89   - }
90   -
91   - .label-span {
92   - width: 10rem;
93   - white-space: nowrap;
94   - text-overflow: ellipsis;
95   - overflow: hidden;
96   - word-break: break-all;
97   - }
98   -</style>
... ... @@ -37,7 +37,7 @@
37 37 },
38 38 legend: {
39 39 top: 'bottom',
40   - padding: 5,
  40 + type: 'scroll',
41 41 },
42 42 title: [
43 43 {
... ...
... ... @@ -3,6 +3,7 @@
3 3 import { useECharts } from '/@/hooks/web/useECharts';
4 4 import { useAppStore } from '/@/store/modules/app';
5 5 import { useI18n } from '/@/hooks/web/useI18n';
  6 + import { Empty } from 'ant-design-vue';
6 7
7 8 const { t } = useI18n();
8 9
... ... @@ -11,6 +12,14 @@
11 12 type: Array,
12 13 default: () => [],
13 14 },
  15 + timeLineXAxisData: {
  16 + type: Array,
  17 + default: () => [],
  18 + },
  19 + timeType: {
  20 + type: String,
  21 + default: 'week',
  22 + },
14 23 });
15 24
16 25 const emits = defineEmits(['emitTimeRange']);
... ... @@ -21,10 +30,11 @@
21 30
22 31 const timeRangeList = ref([
23 32 { label: `1${t('home.index.timeUnit.hour')}`, value: 'hour', interval: 1000 * 60 * 5 },
  33 + { label: `1${t('home.index.timeUnit.day')}`, value: 'day', interval: 1000 * 60 * 60 * 1 },
24 34 {
25 35 label: `7${t('home.index.timeUnit.day')}`,
26 36 value: 'week',
27   - interval: 1000 * 60 * 60 * 2,
  37 + interval: 1000 * 60 * 60 * 1,
28 38 },
29 39 {
30 40 label: `30${t('home.index.timeUnit.day')}`,
... ... @@ -63,7 +73,12 @@
63 73 show: false,
64 74 },
65 75 axisLabel: {
66   - formatter: '{yyyy}-{MM}-{dd}',
  76 + formatter:
  77 + props.timeType === 'hour'
  78 + ? '{yyyy}-{MM}-{dd} {HH}:{mm}:{ss}'
  79 + : props.timeType === 'day'
  80 + ? '{yyyy}-{MM}-{dd} {HH}:{mm}:{ss}'
  81 + : '{yyyy}-{MM}-{dd}',
67 82 showMinLabel: true,
68 83 showMaxLabel: true, // 固定显示X轴的最后一条数据
69 84 },
... ... @@ -95,13 +110,17 @@
95 110 },
96 111 {
97 112 deep: true,
  113 + immediate: true,
98 114 }
99 115 );
100 116
101 117 onMounted(() => {
102 118 setOptions(getOptions());
103 119 //自适应
104   - window.addEventListener('resize', () => resize());
  120 + window.addEventListener('resize', () => {
  121 + resize();
  122 + setOptions(getOptions());
  123 + });
105 124 });
106 125
107 126 const handleTimeRangeChange = (e: any) => {
... ... @@ -122,7 +141,10 @@
122 141 </template>
123 142 </a-radio-group>
124 143 </template>
125   - <div ref="chartRef" class="w-full h-80"></div>
  144 + <div v-show="seriesData.length" ref="chartRef" class="w-full h-80"></div>
  145 + <div v-show="!seriesData.length" class="w-full h-72 flex justify-center items-center"
  146 + ><Empty :image="Empty.PRESENTED_IMAGE_SIMPLE"
  147 + /></div>
126 148 </a-card>
127 149 </template>
128 150
... ...
1 1 <script setup lang="ts">
  2 + import { ref } from 'vue';
2 3 import LineChart from './components/LineChart.vue';
3 4 import PieChart from './components/PieChart.vue';
4 5 import Table from './components/Table.vue';
... ... @@ -27,6 +28,7 @@
27 28 pieChartData: Recordable[];
28 29 timeLineChartData: Recordable[];
29 30 totalData: Recordable[];
  31 + timeLineXAxisData?: string[];
30 32 }
31 33
32 34 const chartData = reactive<ChartData>({
... ... @@ -34,6 +36,7 @@
34 36 pieChartData: [],
35 37 timeLineChartData: [],
36 38 totalData: [],
  39 + timeLineXAxisData: [],
37 40 });
38 41
39 42 // API统计
... ... @@ -76,15 +79,92 @@
76 79 ?.map((topItem) => topItem.value)
77 80 ?.reduce((sum, curr) => sum + curr);
78 81 // 相加总共
79   - chartData.pieChartData.push({
80   - name: '其他应用',
81   - value: res.tops.length <= 5 ? 0 : otherApplicationCount,
82   - });
  82 + if (res.tops && res.tops.length > 5) {
  83 + chartData.pieChartData.push({
  84 + name: '其他应用',
  85 + value: otherApplicationCount,
  86 + });
  87 + }
83 88 }
84 89 };
85 90
  91 + //1小时->5分钟间隔 1天->2小时间隔 7天->1天间隔 30天->1天间隔
  92 + const timeFormat = (type, config) => {
  93 + let startT: any = null;
  94 + let endT: any = null;
  95 + let interval: any = null; //分割间隔
  96 + if (type == 'hour') {
  97 + interval = 5;
  98 + startT = moment().subtract(1, config.text);
  99 + endT = moment().format('HH:mm');
  100 + } else if (type == 'day') {
  101 + interval = 2;
  102 + startT = moment().subtract(1, config.text);
  103 + endT = moment().format('HH:mm');
  104 + } else if (type == 'week') {
  105 + interval = 1;
  106 + startT = moment().subtract(1, config.text);
  107 + endT = moment().format('HH:mm');
  108 + } else if (type == 'month') {
  109 + interval = 1;
  110 + startT = moment().subtract(1, config.text);
  111 + endT = moment().format('HH:mm');
  112 + }
  113 + let starTime = moment(startT, 'HH:mm');
  114 + let endTime = moment(endT, 'HH:mm');
  115 + let diff = endTime.diff(starTime, config.diffText);
  116 + let num = Math.ceil(diff / interval);
  117 + let times: any = [];
  118 + for (let i = 1; i <= num; i++) {
  119 + let timeFrom = starTime.clone().add((i - 1) * interval, config.timeText) as any;
  120 + times.push(timeFrom.format('YYYY-MM-DD HH:mm'));
  121 + }
  122 + return times;
  123 + };
  124 +
  125 + const configTime = [
  126 + {
  127 + name: 'hour',
  128 + value: {
  129 + text: 'hours',
  130 + diffText: 'minutes',
  131 + timeText: 'minutes',
  132 + },
  133 + },
  134 + {
  135 + name: 'day',
  136 + value: {
  137 + text: 'days',
  138 + diffText: 'hours',
  139 + timeText: 'hours',
  140 + },
  141 + },
  142 + {
  143 + name: 'week',
  144 + value: {
  145 + text: 'weeks',
  146 + diffText: 'days',
  147 + timeText: 'days',
  148 + },
  149 + },
  150 + {
  151 + name: 'month',
  152 + value: {
  153 + text: 'months',
  154 + diffText: 'days',
  155 + timeText: 'days',
  156 + },
  157 + },
  158 + ];
  159 + //代码保留
  160 +
  161 + const timeType = ref('');
  162 +
86 163 // 接口调用历史
87 164 const getClassify = async (type?: string) => {
  165 + timeType.value = type as string;
  166 + const findValue = configTime.find((configItem) => configItem.name === type)?.value;
  167 + chartData.timeLineXAxisData = timeFormat(type, findValue);
88 168 const res = (await getApplicationRecordClassify(type)) as any as ClassifyItemType[];
89 169 chartData.timeLineChartData = res?.map((classifyItem: ClassifyItemType) => ({
90 170 type: 'line',
... ... @@ -125,15 +205,11 @@
125 205 </div>
126 206 <div>
127 207 <TimeLineChart
128   - v-if="chartData.timeLineChartData.length"
129 208 @emitTimeRange="handleReceiveTimeRange"
130 209 :seriesData="chartData.timeLineChartData"
  210 + :timeLineXAxisData="chartData.timeLineXAxisData"
  211 + :timeType="timeType"
131 212 />
132   - <a-card v-else :title="t('application.record.text.timeLineTitle')" class="w-full h-120">
133   - <div class="w-full h-72 flex justify-center items-center"
134   - ><Empty :image="Empty.PRESENTED_IMAGE_SIMPLE"
135   - /></div>
136   - </a-card>
137 213 </div>
138 214 <div>
139 215 <a-card class="w-full h-140">
... ...