Commit b764a3987caa5570a36e728d0d8eafd0bb1c767a

Authored by ww
2 parents 6688ab22 e116f65d

Merge branch 'perf/openapi/24-10-09' into main_dev

1   -import { ApplicationRecordPageParams, CallStatisticsItemType } from './model/record';
  1 +import {
  2 + ApplicationRecordPageParams,
  3 + CallStatisticsItemType,
  4 + ClassifyItemType,
  5 +} from './model/record';
2 6 import { PaginationResult } from '/#/axios';
3 7 import { defHttp } from '/@/utils/http/axios';
4 8
... ... @@ -40,7 +44,7 @@ export const getApplicationRecordTop = () => {
40 44
41 45 export const getApplicationRecordClassify = (type?: string) => {
42 46 const joinUrlParams = type ? `?type=${type}` : '';
43   - return defHttp.get({
  47 + return defHttp.get<ClassifyItemType[]>({
44 48 url: `${ApplicationRecordManageApi.OPEN_API_RECORD}/getClassify${joinUrlParams}`,
45 49 });
46 50 };
... ...
... ... @@ -4,23 +4,20 @@
4 4 import { useAppStore } from '/@/store/modules/app';
5 5 import { useI18n } from '/@/hooks/web/useI18n';
6 6 import { Empty } from 'ant-design-vue';
  7 + import { EChartsOption, SeriesOption } from 'echarts';
7 8
8 9 const { t } = useI18n();
9 10
10   - const props = defineProps({
11   - seriesData: {
12   - type: Array,
13   - default: () => [],
14   - },
15   - timeLineXAxisData: {
16   - type: Array,
17   - default: () => [],
18   - },
19   - timeType: {
20   - type: String,
21   - default: 'week',
22   - },
23   - });
  11 + const props = withDefaults(
  12 + defineProps<{
  13 + timeType: string;
  14 + chartsData?: Partial<EChartsOption>;
  15 + }>(),
  16 + {
  17 + timeType: 'week',
  18 + chartsData: () => ({}),
  19 + }
  20 + );
24 21
25 22 const emits = defineEmits(['emitTimeRange']);
26 23
... ... @@ -51,7 +48,8 @@
51 48
52 49 const { setOptions, resize } = useECharts(chartRef as Ref<HTMLDivElement>);
53 50
54   - const getOptions: any = () => {
  51 + const getOptions = (): EChartsOption => {
  52 + const { xAxis, series } = props.chartsData || {};
55 53 return {
56 54 backgroundColor: skinName.value,
57 55 tooltip: {
... ... @@ -63,31 +61,12 @@
63 61 bottom: '1%',
64 62 containLabel: true,
65 63 },
66   - xAxis: {
67   - type: 'time',
68   - splitLine: { show: false },
69   - lineStyle: {
70   - width: 2,
71   - },
72   - axisTick: {
73   - show: false,
74   - },
75   - axisLabel: {
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}',
82   - showMinLabel: true,
83   - showMaxLabel: true, // 固定显示X轴的最后一条数据
84   - },
85   - },
  64 + xAxis,
86 65 yAxis: {
87 66 type: 'value',
88 67 axisLabel: { formatter: '{value}' },
89 68 },
90   - series: props.seriesData,
  69 + series,
91 70 };
92 71 };
93 72
... ... @@ -104,7 +83,7 @@
104 83 );
105 84
106 85 watch(
107   - () => props.seriesData,
  86 + () => props.chartsData,
108 87 () => {
109 88 setOptions(getOptions());
110 89 },
... ... @@ -141,10 +120,17 @@
141 120 </template>
142 121 </a-radio-group>
143 122 </template>
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>
  123 + <div
  124 + v-show="(chartsData?.series as SeriesOption[])?.length"
  125 + ref="chartRef"
  126 + class="w-full h-80"
  127 + ></div>
  128 + <div
  129 + v-show="!(chartsData?.series as SeriesOption[])?.length"
  130 + class="w-full h-72 flex justify-center items-center"
  131 + >
  132 + <Empty :image="Empty.PRESENTED_IMAGE_SIMPLE" />
  133 + </div>
148 134 </a-card>
149 135 </template>
150 136
... ...
  1 +import { EChartsOption } from 'echarts';
  2 +import { formatClassifyText } from '../../api/config';
  3 +import { ClassifyDtsItemType, ClassifyItemType } from '/@/api/application/model/record';
1 4 import { DescItem } from '/@/components/Description';
2 5 import { BasicColumn } from '/@/components/Table';
3 6 import { useI18n } from '/@/hooks/web/useI18n';
  7 +import { dateUtil } from '/@/utils/dateUtil';
  8 +
  9 +export type DateInterval = 'hour' | 'day' | 'week' | 'month';
4 10
5 11 const { t } = useI18n();
6 12
... ... @@ -45,3 +51,85 @@ export const formSchema: DescItem[] = [
45 51 label: t('application.record.text.numberOfFailedAttempts'),
46 52 },
47 53 ];
  54 +
  55 +function generateFullXAxis(type: DateInterval) {
  56 + if (type === 'hour') {
  57 + return Array.from({ length: 60 / 5 }, (_, index) =>
  58 + dateUtil()
  59 + .subtract(index * 5, 'minute')
  60 + .startOf('minute')
  61 + .valueOf()
  62 + );
  63 + } else if (type === 'day') {
  64 + return Array.from({ length: 24 / 2 }, (_, index) =>
  65 + dateUtil()
  66 + .subtract(index * 2, 'hour')
  67 + .startOf('hour')
  68 + .valueOf()
  69 + );
  70 + } else if (type === 'week') {
  71 + return Array.from({ length: 7 }, (_, index) =>
  72 + dateUtil().subtract(index, 'day').startOf('day').valueOf()
  73 + );
  74 + } else {
  75 + return Array.from({ length: 30 }, (_, index) =>
  76 + dateUtil().subtract(index, 'day').startOf('day').valueOf()
  77 + );
  78 + }
  79 +}
  80 +
  81 +export function formatDateFromType(date: number, type: DateInterval) {
  82 + if (type === 'hour') {
  83 + return dateUtil(date).format('YYYY-MM-DD HH:mm');
  84 + } else if (type === 'day') {
  85 + return dateUtil(date).format('YYYY-MM-DD HH:mm');
  86 + } else {
  87 + return dateUtil(date).format('YYYY-MM-DD');
  88 + }
  89 +}
  90 +
  91 +export function transformClassifyItem(data: ClassifyItemType[], type: DateInterval) {
  92 + const res: ClassifyItemType[] = [];
  93 + const fullXAxis = generateFullXAxis(type);
  94 +
  95 + for (const { dts, classify } of data) {
  96 + const valueMap = dts.reduce((prev, next) => {
  97 + const key = dateUtil(next.time).valueOf();
  98 +
  99 + return { ...prev, [key]: next };
  100 + }, {} as Record<number, ClassifyDtsItemType>);
  101 +
  102 + const transformDts: ClassifyDtsItemType[] = fullXAxis.map((timeSpan) => {
  103 + const exist = valueMap[timeSpan];
  104 +
  105 + return exist || { time: formatDateFromType(timeSpan, type), count: 0, classify };
  106 + });
  107 +
  108 + res.push({ classify, dts: transformDts });
  109 + }
  110 +
  111 + return res;
  112 +}
  113 +
  114 +export function transformChartsOptionsByClassifyRecord(
  115 + data: ClassifyItemType[],
  116 + type: DateInterval
  117 +): Partial<EChartsOption> {
  118 + const series: EChartsOption['series'] = data.map(({ classify, dts }) => {
  119 + return {
  120 + type: 'line',
  121 + name: formatClassifyText[classify],
  122 + data: dts.map(({ count }) => count),
  123 + };
  124 + });
  125 +
  126 + const xAxisData = generateFullXAxis(type).map((timeSpan) => formatDateFromType(timeSpan, type));
  127 +
  128 + return {
  129 + series: series.reverse(),
  130 + xAxis: {
  131 + type: 'category',
  132 + data: xAxisData.reverse(),
  133 + },
  134 + };
  135 +}
... ...
... ... @@ -8,35 +8,32 @@
8 8 import { useI18n } from '/@/hooks/web/useI18n';
9 9 import { onMounted, reactive } from 'vue';
10 10 import { getApplicationRecordClassify, getApplicationRecordTop } from '/@/api/application/record';
11   - import {
12   - ApplicationRecordTopItemType,
13   - ClassifyDtsItemType,
14   - ClassifyItemType,
15   - TopItemType,
16   - } from '/@/api/application/model/record';
  11 + import { ApplicationRecordTopItemType, TopItemType } from '/@/api/application/model/record';
17 12 import { Empty } from 'ant-design-vue';
18   - import moment from 'moment';
19   - import { formatClassifyText } from '../api/config';
20 13 import total1 from '/@/assets/images/total1.png';
21 14 import total2 from '/@/assets/images/total2.png';
22 15 import total3 from '/@/assets/images/total3.png';
  16 + import {
  17 + DateInterval,
  18 + transformClassifyItem,
  19 + transformChartsOptionsByClassifyRecord,
  20 + } from './config';
  21 + import { EChartsOption } from 'echarts';
23 22
24 23 const { t } = useI18n();
25 24
26 25 interface ChartData {
27 26 lineChartData: Recordable[];
28 27 pieChartData: Recordable[];
29   - timeLineChartData: Recordable[];
30 28 totalData: Recordable[];
31   - timeLineXAxisData?: string[];
  29 + timeLineChartOptions?: Partial<EChartsOption>;
32 30 }
33 31
34 32 const chartData = reactive<ChartData>({
35 33 lineChartData: [],
36 34 pieChartData: [],
37   - timeLineChartData: [],
38 35 totalData: [],
39   - timeLineXAxisData: [],
  36 + timeLineChartOptions: {},
40 37 });
41 38
42 39 // API统计
... ... @@ -88,96 +85,20 @@
88 85 }
89 86 };
90 87
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 88 const timeType = ref('');
162 89
163 90 // 接口调用历史
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);
168   - const res = (await getApplicationRecordClassify(type)) as any as ClassifyItemType[];
169   - chartData.timeLineChartData = res?.map((classifyItem: ClassifyItemType) => ({
170   - type: 'line',
171   - name: formatClassifyText[classifyItem.classify],
172   - data: classifyItem?.dts?.map((dtsItem: ClassifyDtsItemType) => [
173   - moment(dtsItem.time).format('YYYY-MM-DD HH:mm:ss'),
174   - dtsItem.count,
175   - ]),
176   - connectNulls: true,
177   - }));
  91 + const getClassify = async (type: DateInterval) => {
  92 + timeType.value = type;
  93 + // const findValue = configTime.find((configItem) => configItem.name === type)?.value;
  94 + // chartData.timeLineXAxisData = timeFormat(type, findValue);
  95 + const res = await getApplicationRecordClassify(type);
  96 +
  97 + const transformData = transformClassifyItem(res, type);
  98 + chartData.timeLineChartOptions = transformChartsOptionsByClassifyRecord(transformData, type);
178 99 };
179 100
180   - const handleReceiveTimeRange = (value: string) => {
  101 + const handleReceiveTimeRange = (value: DateInterval) => {
181 102 getClassify(value);
182 103 };
183 104
... ... @@ -192,22 +113,21 @@
192 113 <Total :seriesData="chartData.totalData" />
193 114 <a-card :title="t('application.record.text.pieTitle')" class="h-99" style="width: 40%">
194 115 <PieChart v-if="chartData.pieChartData.length" :seriesData="chartData.pieChartData" />
195   - <div class="w-full h-72 flex justify-center items-center" v-else
196   - ><Empty :image="Empty.PRESENTED_IMAGE_SIMPLE"
197   - /></div>
  116 + <div class="w-full h-72 flex justify-center items-center" v-else>
  117 + <Empty :image="Empty.PRESENTED_IMAGE_SIMPLE" />
  118 + </div>
198 119 </a-card>
199 120 <a-card :title="t('application.record.text.lineTitle')" class="h-99" style="width: 45%">
200 121 <LineChart v-if="chartData.lineChartData.length" :seriesData="chartData.lineChartData" />
201   - <div class="w-full h-72 flex justify-center items-center" v-else
202   - ><Empty :image="Empty.PRESENTED_IMAGE_SIMPLE"
203   - /></div>
  122 + <div class="w-full h-72 flex justify-center items-center" v-else>
  123 + <Empty :image="Empty.PRESENTED_IMAGE_SIMPLE" />
  124 + </div>
204 125 </a-card>
205 126 </div>
206 127 <div>
207 128 <TimeLineChart
208 129 @emitTimeRange="handleReceiveTimeRange"
209   - :seriesData="chartData.timeLineChartData"
210   - :timeLineXAxisData="chartData.timeLineXAxisData"
  130 + :charts-data="(chartData.timeLineChartOptions as EChartsOption)"
211 131 :timeType="timeType"
212 132 />
213 133 </div>
... ...