Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yudao-admin-ui
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
licheng
yudao-admin-ui
Commits
fa79ae06
Commit
fa79ae06
authored
Aug 26, 2025
by
licheng
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 瀑布图
parent
e898d322
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
70 additions
and
128 deletions
+70
-128
.env.local
.env.local
+1
-1
Index2.vue
src/views/Home/Index2.vue
+66
-127
echarts-data.ts
src/views/Home/echarts-data.ts
+3
-0
No files found.
.env.local
View file @
fa79ae06
...
@@ -4,7 +4,7 @@ NODE_ENV=development
...
@@ -4,7 +4,7 @@ NODE_ENV=development
VITE_DEV=true
VITE_DEV=true
# 请求路径
# 请求路径
VITE_BASE_URL='http://192.168.0.253:
252
80'
VITE_BASE_URL='http://192.168.0.253:
480
80'
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务
VITE_UPLOAD_TYPE=server
VITE_UPLOAD_TYPE=server
...
...
src/views/Home/Index2.vue
View file @
fa79ae06
<
template
>
<
template
>
<el-card
class=
"mb-20px"
shadow=
"hover"
>
<el-card
class=
"mb-20px relative"
shadow=
"hover"
>
<div
class=
"absolute right-2 top-2 text-xs text-gray-500 z-10"
>
数据:
{{
lineInfo
.
size
}}
条 | FPS:
{{
lineInfo
.
fps
}}
</div>
<el-skeleton
:loading=
"loading"
:rows=
"4"
animated
>
<el-skeleton
:loading=
"loading"
:rows=
"4"
animated
>
<Echart
:height=
"350"
:options=
"lineOptionsData"
/>
<Echart
:height=
"350"
:options=
"lineOptionsData"
/>
</el-skeleton>
</el-skeleton>
</el-card>
</el-card>
<el-card
class=
"mb-20px px-[40px] relative"
shadow=
"hover"
>
<div
class=
"absolute right-2 top-2 text-xs text-gray-500 z-10"
>
大小:
{{
waterfallInfo
.
size
}}
| FPS:
{{
waterfallInfo
.
fps
}}
</div>
<el-skeleton
:loading=
"loading"
:rows=
"4"
animated
>
<div
class=
"flex justify-center font-700 text-[18px] mb-2"
>
瀑布图
</div>
<img
id=
"waterfall"
:src=
"waterfallImg"
alt=
"waterfall"
class=
"w-full h-[200px]"
/>
</el-skeleton>
</el-card>
</
template
>
</
template
>
<
script
lang=
"ts"
setup
>
<
script
lang=
"ts"
setup
>
import
{
set
}
from
'lodash-es'
import
{
set
}
from
'lodash-es'
import
{
EChartsOption
}
from
'echarts'
import
{
EChartsOption
}
from
'echarts'
import
'echarts/lib/component/dataZoom'
import
'echarts/lib/component/dataZoom'
import
{
lineOptions
}
from
'./echarts-data'
import
{
lineOptions
}
from
'./echarts-data'
defineOptions
({
name
:
'Home2'
})
defineOptions
({
name
:
'Home2'
})
...
@@ -19,10 +32,24 @@ const loading = ref(true)
...
@@ -19,10 +32,24 @@ const loading = ref(true)
const
lineOptionsData
=
reactive
<
EChartsOption
>
(
lineOptions
)
as
EChartsOption
const
lineOptionsData
=
reactive
<
EChartsOption
>
(
lineOptions
)
as
EChartsOption
let
data
:
any
[]
=
[]
// 波形图数据
let
data
:
any
[]
=
[]
// 波形图数据
const
waterfallImg
=
ref
(
''
)
// 瀑布图图片
// 左上角显示用的数据
const
lineInfo
=
ref
({
size
:
0
,
fps
:
0
})
const
waterfallInfo
=
ref
({
size
:
'0 KB'
,
fps
:
0
})
// FPS 统计
let
lineFrameCount
=
0
let
waterfallFrameCount
=
0
setInterval
(()
=>
{
lineInfo
.
value
.
fps
=
lineFrameCount
waterfallInfo
.
value
.
fps
=
waterfallFrameCount
lineFrameCount
=
0
waterfallFrameCount
=
0
},
1000
)
// 初始数据
// 初始数据
const
getLineData
=
async
()
=>
{
const
getLineData
=
async
()
=>
{
// data = createData(1000000, 1)
set
(
set
(
lineOptionsData
,
lineOptionsData
,
'xAxis.data'
,
'xAxis.data'
,
...
@@ -31,87 +58,69 @@ const getLineData = async () => {
...
@@ -31,87 +58,69 @@ const getLineData = async () => {
set
(
lineOptionsData
,
'series'
,
[
set
(
lineOptionsData
,
'series'
,
[
{
{
name
:
'data1'
,
name
:
'data1'
,
smooth
:
false
,
// 是否平滑曲线
smooth
:
false
,
type
:
'line'
,
type
:
'line'
,
showSymbol
:
false
,
// 不显示数据点
showSymbol
:
false
,
progressive
:
1000
,
// 每次增量渲染的数据量
progressive
:
1000
,
progressiveThreshold
:
5000
,
// 总数据量超过此值触发增量渲染
progressiveThreshold
:
5000
,
lineStyle
:
{
lineStyle
:
{
width
:
1
// 细线
width
:
1
},
},
sampling
:
'lttb'
,
// 使用 LTTB 采样算法降低数据量
sampling
:
'lttb'
,
// samplingThreshold: 10000, // 采样阈值,超过此值将进行采样
animation
:
false
,
animation
:
false
,
// 动画
animationDuration
:
1000
,
animationDuration
:
1000
,
// 动画持续时间
animationEasing
:
'linear'
,
animationEasing
:
'linear'
,
// 动画缓动效果
data
:
data
.
map
((
v
)
=>
v
.
data1
)
data
:
data
.
map
((
v
)
=>
v
.
data1
)
}
}
// {
// name: 'data2',
// smooth: false, // 是否平滑曲线
// type: 'line',
// showSymbol: false, // 不显示数据点
// progressive: 1000, // 每次增量渲染的数据量
// progressiveThreshold: 5000, // 总数据量超过此值触发增量渲染
// animation: false, // 关闭动画
// lineStyle: {
// width: 0.5 // 细线
// },
// sampling: 'lttb', // 使用 LTTB 采样算法
// samplingThreshold: 10000, // 采样阈值,超过此值将进行采样
// data: data.map((v) => v.data2)
// }
])
])
}
}
const
connect
=
()
=>
{
const
connect
=
()
=>
{
// 连接到 WebSocket 服务器(替换成你的服务器地址)
const
socket
=
new
WebSocket
(
'ws://localhost:8025/ws/combined'
)
const
socket
=
new
WebSocket
(
'ws://localhost:8080'
)
//
const socket = new WebSocket('ws://localhost:8080')
// 监听连接成功
socket
.
addEventListener
(
'open'
,
()
=>
{
socket
.
addEventListener
(
'open'
,
(
event
)
=>
{
console
.
log
(
'WebSocket 连接成功'
)
console
.
log
(
'WebSocket 连接成功'
)
})
})
// 接收服务器消息
socket
.
addEventListener
(
'message'
,
(
event
)
=>
{
socket
.
addEventListener
(
'message'
,
(
event
)
=>
{
const
newData
=
JSON
.
parse
(
event
.
data
)
const
parsed
=
JSON
.
parse
(
event
.
data
)
const
newData
=
parsed
.
lineData
// 更新瀑布图
waterfallImg
.
value
=
`data:image/png;base64,
${
parsed
.
waterfallImg
}
`
// ---- 更新波形图信息 ----
lineInfo
.
value
.
size
=
newData
.
length
lineFrameCount
++
// ---- 更新瀑布图信息 (计算 base64 大小) ----
const
base64Str
=
parsed
.
waterfallImg
const
strLen
=
base64Str
.
length
const
fileSizeKB
=
(
strLen
*
3
/
4
/
1024
).
toFixed
(
2
)
waterfallInfo
.
value
.
size
=
`
${
fileSizeKB
}
KB`
waterfallFrameCount
++
// 更新图表数据
// 更新图表数据
const
newXAxisData
=
[...
lineOptionsData
!
.
xAxis
!
.
data
,
...
newData
.
map
((
item
)
=>
item
.
name
)]
const
newXAxisData
=
newData
.
map
((
item
)
=>
item
.
frequency
)
console
.
log
(
newXAxisData
.
length
)
set
(
lineOptionsData
,
'xAxis.data'
,
newXAxisData
)
set
(
lineOptionsData
,
'xAxis.data'
,
newXAxisData
)
set
(
lineOptionsData
,
'series'
,
[
set
(
lineOptionsData
,
'series'
,
[
{
{
name
:
'data1'
,
name
:
'data1'
,
smooth
:
false
,
smooth
:
false
,
type
:
'line'
,
type
:
'line'
,
// 启用大数据优化
progressive
:
1000
,
progressive
:
1000
,
progressiveThreshold
:
5000
,
progressiveThreshold
:
5000
,
showSymbol
:
false
,
// 不显示数据点
showSymbol
:
false
,
lineStyle
:
{
lineStyle
:
{
width
:
0.5
// 细线
width
:
0.5
},
},
sampling
:
'lttb'
,
// 使用 LTTB 采样算法
sampling
:
'lttb'
,
animation
:
false
,
// 动画
animation
:
false
,
animationDuration
:
1000
,
// 动画持续时间
animationDuration
:
1000
,
animationEasing
:
'linear'
,
// 动画缓动效果
animationEasing
:
'linear'
,
data
:
[...
lineOptionsData
!
.
series
!
[
0
].
data
,
...
newData
.
map
((
item
)
=>
item
.
data1
)]
data
:
[...
newData
.
map
((
item
)
=>
item
.
value
)]
}
}
// {
// name: 'data2',
// smooth: false,
// type: 'line',
// itemStyle: {},
// // 启用大数据优化
// progressive: 1000,
// progressiveThreshold: 5000,
// lineStyle: {
// width: 0.5 // 细线
// },
// data: [...lineOptionsData.series[1].data, ...newData.map((item) => item.data2)]
// }
])
])
})
})
}
}
...
@@ -123,76 +132,6 @@ const getAllApi = async () => {
...
@@ -123,76 +132,6 @@ const getAllApi = async () => {
}
}
getAllApi
()
getAllApi
()
interface
DataItem
{
[
key
:
string
]:
number
|
string
name
:
string
}
function
formatDate
(
date
:
Date
,
format
:
string
):
string
{
const
pad
=
(
num
:
number
)
=>
num
.
toString
().
padStart
(
2
,
'0'
)
return
format
.
replace
(
'HH'
,
pad
(
date
.
getHours
()))
.
replace
(
'mm'
,
pad
(
date
.
getMinutes
()))
.
replace
(
'ss'
,
pad
(
date
.
getSeconds
()))
}
function
createData
(
count
:
number
,
dataCount
:
1
|
2
|
3
=
2
,
minValue
:
number
=
50
,
maxValue
:
number
=
250
):
DataItem
[]
{
const
result
:
DataItem
[]
=
[]
const
now
=
new
Date
()
// 生成时间点(从当前时间往前递减)
const
timeStamps
:
Date
[]
=
[]
for
(
let
i
=
count
-
1
;
i
>=
0
;
i
--
)
{
const
time
=
new
Date
(
now
.
getTime
()
-
i
*
1000
)
timeStamps
.
push
(
time
)
}
// 初始化各数据项的值和方向
const
dataValues
:
Record
<
string
,
number
>
=
{}
const
dataDirections
:
Record
<
string
,
number
>
=
{}
for
(
let
i
=
1
;
i
<=
dataCount
;
i
++
)
{
const
key
=
`data
${
i
}
`
dataValues
[
key
]
=
minValue
+
Math
.
random
()
*
(
maxValue
-
minValue
)
// 初始随机值
dataDirections
[
key
]
=
Math
.
random
()
>
0.5
?
1
:
-
1
// 随机初始方向
}
for
(
let
i
=
0
;
i
<
count
;
i
++
)
{
const
item
:
DataItem
=
{
name
:
formatDate
(
timeStamps
[
i
],
'HH:mm:ss'
)
}
// 为每个数据项生成波形数据
for
(
let
j
=
1
;
j
<=
dataCount
;
j
++
)
{
const
key
=
`data
${
j
}
`
const
change
=
10
+
Math
.
random
()
*
30
// 变化幅度10~40(可调整)
// 随机决定是否改变方向(更自然的波动)
if
(
Math
.
random
()
<
0.2
)
{
// 20%概率改变方向
dataDirections
[
key
]
*=
-
1
}
dataValues
[
key
]
+=
dataDirections
[
key
]
*
change
// 限制在合理范围内(但不强制反转)
dataValues
[
key
]
=
Math
.
max
(
minValue
*
0.9
,
// 允许稍微低于最小值(避免卡边界)
Math
.
min
(
maxValue
*
1.1
,
dataValues
[
key
])
// 允许稍微高于最大值
)
item
[
key
]
=
Math
.
round
(
dataValues
[
key
])
}
result
.
push
(
item
)
}
return
result
}
</
script
>
</
script
>
<
style
lang=
"scss"
scoped
></
style
>
<
style
lang=
"scss"
scoped
></
style
>
src/views/Home/echarts-data.ts
View file @
fa79ae06
...
@@ -27,6 +27,9 @@ export const lineOptions: EChartsOption = {
...
@@ -27,6 +27,9 @@ export const lineOptions: EChartsOption = {
axisPointer
:
{
axisPointer
:
{
type
:
'cross'
type
:
'cross'
},
},
// position: function (pt) {
// return [pt[0], '10%'];
// },
padding
:
[
5
,
10
]
padding
:
[
5
,
10
]
},
},
yAxis
:
{
yAxis
:
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment