Skip to content

Commit 75edcf4

Browse files
committed
Merge branch 'fix/space-analytics-frontend' into dev
2 parents e35fff6 + 8cd4009 commit 75edcf4

4 files changed

Lines changed: 251 additions & 184 deletions

File tree

src/components/analytics/AnalyticsChart.vue

Lines changed: 67 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,74 @@
44
{{ title }}
55
</v-card-title>
66
<v-card-text>
7-
<div v-if="chartType === 'pie'" class="pie-chart">
7+
<div v-if="!data || data.length === 0" class="text-center py-8 text-medium-emphasis">
8+
暂无数据
9+
</div>
10+
<div v-else-if="chartType === 'pie'" class="pie-chart">
811
<svg :width="size" :height="size" viewBox="0 0 200 200">
912
<g transform="translate(100, 100)">
10-
<path
13+
<g
1114
v-for="(segment, index) in pieSegments"
1215
:key="index"
13-
:d="segment.path"
14-
:fill="colors[index % colors.length]"
15-
:stroke="'white'"
16-
:stroke-width="2"
17-
/>
16+
:class="['pie-segment', { 'pie-segment-hover': hoveredSegment === index }]"
17+
@mouseenter="hoveredSegment = index"
18+
@mouseleave="hoveredSegment = null"
19+
>
20+
<path
21+
:d="segment.path"
22+
:fill="colors[index % colors.length]"
23+
:stroke="'white'"
24+
:stroke-width="2"
25+
:transform="hoveredSegment === index ? 'scale(1.05)' : 'scale(1)'"
26+
style="cursor: pointer; transition: transform 0.2s ease"
27+
/>
28+
<title>{{ data[index].label }}: {{ data[index].count }} ({{ data[index].percentage.toFixed(1) }}%)</title>
29+
</g>
1830
</g>
1931
</svg>
2032
</div>
2133

22-
<div v-else-if="chartType === 'bar'" class="bar-chart">
23-
<svg :width="size" :height="size" viewBox="0 0 400 200">
24-
<g transform="translate(40, 160)">
25-
<rect
26-
v-for="(item, index) in data"
27-
:key="index"
28-
:x="index * barWidth"
29-
:y="-item.percentage * 1.5"
30-
:width="barWidth - 10"
31-
:height="item.percentage * 1.5"
32-
:fill="colors[index % colors.length]"
33-
/>
34-
<text
35-
v-for="(item, index) in data"
36-
:key="`label-${index}`"
37-
:x="index * barWidth + (barWidth - 10) / 2"
38-
:y="20"
39-
text-anchor="middle"
40-
font-size="12"
41-
class="chart-label"
42-
>
43-
{{ item.label }}
44-
</text>
34+
<div v-else-if="chartType === 'bar'" class="bar-chart d-flex justify-center">
35+
<svg :width="400" :height="250" viewBox="0 0 400 250">
36+
<g transform="translate(50, 200)">
37+
<g v-for="(item, index) in data" :key="index">
38+
<rect
39+
:x="index * (300 / data.length) + 10"
40+
:y="-Math.max(item.count * 10, 20)"
41+
:width="Math.min(barWidth, 50)"
42+
:height="Math.max(item.count * 10, 20)"
43+
:fill="colors[index % colors.length]"
44+
:opacity="hoveredBar === index ? 1 : 0.8"
45+
:transform="hoveredBar === index ? `translate(0, -5)` : 'translate(0, 0)'"
46+
style="cursor: pointer; transition: all 0.2s ease"
47+
@mouseenter="hoveredBar = index"
48+
@mouseleave="hoveredBar = null"
49+
/>
50+
<text
51+
:x="index * (300 / data.length) + 10 + Math.min(barWidth, 50) / 2"
52+
:y="15"
53+
text-anchor="middle"
54+
font-size="12"
55+
class="chart-label"
56+
>
57+
{{ item.label }}
58+
</text>
59+
<text
60+
:x="index * (300 / data.length) + 10 + Math.min(barWidth, 50) / 2"
61+
:y="-Math.max(item.count * 10, 20) - 5"
62+
text-anchor="middle"
63+
font-size="12"
64+
font-weight="bold"
65+
:fill="hoveredBar === index ? colors[index % colors.length] : '#666'"
66+
>
67+
{{ item.count }}
68+
</text>
69+
<title>{{ item.label }}: {{ item.count }}</title>
70+
</g>
71+
<!-- Y轴 -->
72+
<line x1="0" y1="0" x2="0" y2="-180" stroke="#ccc" stroke-width="1" />
73+
<!-- X轴 -->
74+
<line x1="0" y1="0" x2="320" y2="0" stroke="#ccc" stroke-width="1" />
4575
</g>
4676
</svg>
4777
</div>
@@ -60,7 +90,7 @@
6090
<script setup lang="ts">
6191
import type { AnalyticsDistributionItem } from '@/network/api/spaces/types'
6292
63-
import { computed } from 'vue'
93+
import { computed, ref } from 'vue'
6494
6595
interface Props {
6696
title: string
@@ -73,6 +103,8 @@ const props = withDefaults(defineProps<Props>(), {
73103
size: 200,
74104
})
75105
106+
const hoveredSegment = ref<number | null>(null)
107+
76108
const colors = [
77109
'#1976D2',
78110
'#2E7D32',
@@ -93,9 +125,12 @@ const colors = [
93125
]
94126
95127
const barWidth = computed(() => {
96-
return Math.min(320 / props.data.length, 60)
128+
if (props.data.length === 0) return 60
129+
return Math.min(60, 320 / props.data.length)
97130
})
98131
132+
const hoveredBar = ref<number | null>(null)
133+
99134
const pieSegments = computed(() => {
100135
if (props.chartType !== 'pie') return []
101136

src/network/Interceptors/hooks/refreshToken.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { AxiosError } from 'axios'
22
import type { ResponseDataType } from '../../types'
33

4-
import ApiInstance from '../../api'
4+
import ApiInstance, { NewApiInstance } from '../../api'
55
import { UserApi } from '../../api/users'
66
import { messageFailed } from '../../utils/showMessage'
77
import { Local } from '../../utils/storage'
@@ -56,7 +56,10 @@ export default async function refreshToken(error: AxiosError<ResponseDataType>)
5656
eventSourceQueue.forEach((cb) => cb(accessToken))
5757
eventSourceQueue.splice(0)
5858
console.log('re-request', config)
59-
return ApiInstance.request<any>(config)
59+
// 根据原始请求的baseURL判断使用哪个API实例
60+
const baseURL = config.baseURL || ''
61+
const apiInstance = baseURL.includes('8080') ? NewApiInstance : ApiInstance
62+
return apiInstance.request<any>(config)
6063
} catch {
6164
messageFailed('请重新登录')
6265
Local.clear()
@@ -71,7 +74,10 @@ export default async function refreshToken(error: AxiosError<ResponseDataType>)
7174
queue.push((newToken: string) => {
7275
Reflect.set(config.headers!, 'Authorization', `Bearer ${newToken}`)
7376
console.log('queue', config)
74-
resolve(ApiInstance.request<any>(config))
77+
// 根据原始请求的baseURL判断使用哪个API实例
78+
const baseURL = config.baseURL || ''
79+
const apiInstance = baseURL.includes('8080') ? NewApiInstance : ApiInstance
80+
resolve(apiInstance.request<any>(config))
7581
})
7682
})
7783
}

src/network/api/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Api from '..'
77
const option: ApiType = {
88
cfg: {
99
baseURL: API_BASE_URL,
10-
timeout: 5000,
10+
timeout: 30000,
1111
},
1212
interceptor: {
1313
responseInterceptor,
@@ -20,7 +20,7 @@ const option: ApiType = {
2020
const newOption: ApiType = {
2121
cfg: {
2222
baseURL: NEW_API_BASE_URL,
23-
timeout: 5000,
23+
timeout: 30000,
2424
},
2525
interceptor: {
2626
responseInterceptor,

0 commit comments

Comments
 (0)