Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
ca791df4
authored
Mar 01, 2025
by
YunaiV
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【代码评审】IoT:首页统计
parent
cc1a025a
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
72 additions
and
112 deletions
+72
-112
src/views/iot/home/index.vue
+72
-112
No files found.
src/views/iot/home/index.vue
View file @
ca791df4
<
template
>
<
template
>
<div
class=
"min-h-full bg-gray-50"
>
<!-- 第一行:统计卡片行 -->
<el-space
direction=
"vertical"
:fill=
"true"
size=
"small"
class=
"w-full p-2"
>
<!-- 统计卡片行 -->
<el-row
:gutter=
"16"
class=
"mb-4"
>
<el-row
:gutter=
"16"
class=
"mb-4"
>
<el-col
:span=
"6"
>
<el-col
:span=
"6"
>
<el-card
class=
"stat-card"
shadow=
"never"
>
<el-card
class=
"stat-card"
shadow=
"never"
>
<div
class=
"flex flex-col"
>
<div
class=
"flex flex-col"
>
<div
class=
"flex justify-between items-center mb-1"
>
<div
class=
"flex justify-between items-center mb-1"
>
<span
class=
"text-gray-500 text-base font-medium"
>
品
类数量
</span>
<span
class=
"text-gray-500 text-base font-medium"
>
分
类数量
</span>
<Icon
icon=
"ep:menu"
class=
"text-[32px] text-blue-400"
/>
<Icon
icon=
"ep:menu"
class=
"text-[32px] text-blue-400"
/>
</div>
</div>
<span
class=
"text-3xl font-bold text-gray-700"
>
{{
statsData
.
productCategoryCount
}}
</span>
<span
class=
"text-3xl font-bold text-gray-700"
>
{{
statsData
.
productCategoryCount
}}
</span>
<el-divider
class=
"my-2"
/>
<el-divider
class=
"my-2"
/>
<div
class=
"flex justify-between items-center text-gray-400 text-sm"
>
<div
class=
"flex justify-between items-center text-gray-400 text-sm"
>
<span>
今日新增
</span>
<span>
今日新增
</span>
<span
class=
"text-green-500"
>
↑
{{
statsData
.
productCategoryTodayCount
}}
</span>
<span
class=
"text-green-500"
>
+
{{
statsData
.
productCategoryTodayCount
}}
</span>
</div>
</div>
</div>
</div>
</el-card>
</el-card>
...
@@ -30,7 +30,7 @@
...
@@ -30,7 +30,7 @@
<el-divider
class=
"my-2"
/>
<el-divider
class=
"my-2"
/>
<div
class=
"flex justify-between items-center text-gray-400 text-sm"
>
<div
class=
"flex justify-between items-center text-gray-400 text-sm"
>
<span>
今日新增
</span>
<span>
今日新增
</span>
<span
class=
"text-green-500"
>
↑
{{
statsData
.
productTodayCount
}}
</span>
<span
class=
"text-green-500"
>
+
{{
statsData
.
productTodayCount
}}
</span>
</div>
</div>
</div>
</div>
</el-card>
</el-card>
...
@@ -46,7 +46,7 @@
...
@@ -46,7 +46,7 @@
<el-divider
class=
"my-2"
/>
<el-divider
class=
"my-2"
/>
<div
class=
"flex justify-between items-center text-gray-400 text-sm"
>
<div
class=
"flex justify-between items-center text-gray-400 text-sm"
>
<span>
今日新增
</span>
<span>
今日新增
</span>
<span
class=
"text-green-500"
>
↑
{{
statsData
.
deviceTodayCount
}}
</span>
<span
class=
"text-green-500"
>
+
{{
statsData
.
deviceTodayCount
}}
</span>
</div>
</div>
</div>
</div>
</el-card>
</el-card>
...
@@ -55,21 +55,23 @@
...
@@ -55,21 +55,23 @@
<el-card
class=
"stat-card"
shadow=
"never"
>
<el-card
class=
"stat-card"
shadow=
"never"
>
<div
class=
"flex flex-col"
>
<div
class=
"flex flex-col"
>
<div
class=
"flex justify-between items-center mb-1"
>
<div
class=
"flex justify-between items-center mb-1"
>
<span
class=
"text-gray-500 text-base font-medium"
>
物模型消息
</span>
<span
class=
"text-gray-500 text-base font-medium"
>
设备消息数
</span>
<Icon
icon=
"ep:message"
class=
"text-[32px] text-teal-400"
/>
<Icon
icon=
"ep:message"
class=
"text-[32px] text-teal-400"
/>
</div>
</div>
<span
class=
"text-3xl font-bold text-gray-700"
>
{{
statsData
.
deviceMessageCount
}}
</span>
<span
class=
"text-3xl font-bold text-gray-700"
>
{{
statsData
.
deviceMessageCount
}}
</span>
<el-divider
class=
"my-2"
/>
<el-divider
class=
"my-2"
/>
<div
class=
"flex justify-between items-center text-gray-400 text-sm"
>
<div
class=
"flex justify-between items-center text-gray-400 text-sm"
>
<span>
今日新增
</span>
<span>
今日新增
</span>
<span
class=
"text-green-500"
>
↑
{{
statsData
.
deviceMessageTodayCount
}}
</span>
<span
class=
"text-green-500"
>
+
{{
statsData
.
deviceMessageTodayCount
}}
</span>
</div>
</div>
</div>
</div>
</el-card>
</el-card>
</el-col>
</el-col>
</el-row>
</el-row>
<!--
图表行 -->
<!-- 第二行:
图表行 -->
<el-row
:gutter=
"16"
class=
"mb-4"
>
<el-row
:gutter=
"16"
class=
"mb-4"
>
<el-col
:span=
"12"
>
<el-col
:span=
"12"
>
<el-card
class=
"chart-card"
shadow=
"never"
>
<el-card
class=
"chart-card"
shadow=
"never"
>
...
@@ -78,7 +80,7 @@
...
@@ -78,7 +80,7 @@
<span
class=
"text-base font-medium text-gray-600"
>
设备数量统计
</span>
<span
class=
"text-base font-medium text-gray-600"
>
设备数量统计
</span>
</div>
</div>
</
template
>
</
template
>
<div
ref=
"chartDeviceNumStat
"
class=
"h-[240px]"
></div>
<div
ref=
"deviceCountChartRef
"
class=
"h-[240px]"
></div>
</el-card>
</el-card>
</el-col>
</el-col>
<el-col
:span=
"12"
>
<el-col
:span=
"12"
>
...
@@ -90,19 +92,19 @@
...
@@ -90,19 +92,19 @@
</
template
>
</
template
>
<el-row
class=
"h-[240px]"
>
<el-row
class=
"h-[240px]"
>
<el-col
:span=
"8"
class=
"flex flex-col items-center"
>
<el-col
:span=
"8"
class=
"flex flex-col items-center"
>
<div
ref=
"chartDeviceOnline
"
class=
"h-[160px] w-full"
></div>
<div
ref=
"deviceOnlineCountChartRef
"
class=
"h-[160px] w-full"
></div>
<div
class=
"text-center mt-2"
>
<div
class=
"text-center mt-2"
>
<span
class=
"text-sm text-gray-600"
>
在线设备
</span>
<span
class=
"text-sm text-gray-600"
>
在线设备
</span>
</div>
</div>
</el-col>
</el-col>
<el-col
:span=
"8"
class=
"flex flex-col items-center"
>
<el-col
:span=
"8"
class=
"flex flex-col items-center"
>
<div
ref=
"chartDeviceOffline
"
class=
"h-[160px] w-full"
></div>
<div
ref=
"deviceOfflineChartRef
"
class=
"h-[160px] w-full"
></div>
<div
class=
"text-center mt-2"
>
<div
class=
"text-center mt-2"
>
<span
class=
"text-sm text-gray-600"
>
离线设备
</span>
<span
class=
"text-sm text-gray-600"
>
离线设备
</span>
</div>
</div>
</el-col>
</el-col>
<el-col
:span=
"8"
class=
"flex flex-col items-center"
>
<el-col
:span=
"8"
class=
"flex flex-col items-center"
>
<div
ref=
"chartDeviceActive
"
class=
"h-[160px] w-full"
></div>
<div
ref=
"deviceActiveChartRef
"
class=
"h-[160px] w-full"
></div>
<div
class=
"text-center mt-2"
>
<div
class=
"text-center mt-2"
>
<span
class=
"text-sm text-gray-600"
>
待激活设备
</span>
<span
class=
"text-sm text-gray-600"
>
待激活设备
</span>
</div>
</div>
...
@@ -112,7 +114,7 @@
...
@@ -112,7 +114,7 @@
</el-col>
</el-col>
</el-row>
</el-row>
<!--
消息统计行 -->
<!-- 第三行:
消息统计行 -->
<el-row>
<el-row>
<el-col
:span=
"24"
>
<el-col
:span=
"24"
>
<el-card
class=
"chart-card"
shadow=
"never"
>
<el-card
class=
"chart-card"
shadow=
"never"
>
...
@@ -128,7 +130,6 @@
...
@@ -128,7 +130,6 @@
<el-date-picker
<el-date-picker
v-model=
"dateRange"
v-model=
"dateRange"
type=
"datetimerange"
type=
"datetimerange"
range-separator=
"至"
range-separator=
"至"
start-placeholder=
"开始时间"
start-placeholder=
"开始时间"
end-placeholder=
"结束时间"
end-placeholder=
"结束时间"
...
@@ -138,35 +139,39 @@
...
@@ -138,35 +139,39 @@
</div>
</div>
</div>
</div>
</
template
>
</
template
>
<div
ref=
"chartMsgStat
"
class=
"h-[300px]"
></div>
<div
ref=
"deviceMessageCountChartRef
"
class=
"h-[300px]"
></div>
</el-card>
</el-card>
</el-col>
</el-col>
</el-row>
</el-row>
</el-space>
<
/div
>
<
!-- TODO 第四行:地图 --
>
</template>
</template>
<
script
setup
lang=
"ts"
name=
"Index"
>
<
script
setup
lang=
"ts"
name=
"Index"
>
import
*
as
echarts
from
'echarts/core'
import
*
as
echarts
from
'echarts/core'
import
{
TooltipComponent
,
LegendComponent
,
TitleComponent
,
ToolboxComponent
,
GridComponent
}
from
'echarts/components'
import
{
import
{
PieChart
,
LineChart
,
GaugeChart
}
from
'echarts/charts'
GridComponent
,
LegendComponent
,
TitleComponent
,
ToolboxComponent
,
TooltipComponent
}
from
'echarts/components'
import
{
GaugeChart
,
LineChart
,
PieChart
}
from
'echarts/charts'
import
{
LabelLayout
,
UniversalTransition
}
from
'echarts/features'
import
{
LabelLayout
,
UniversalTransition
}
from
'echarts/features'
import
{
CanvasRenderer
}
from
'echarts/renderers'
import
{
CanvasRenderer
}
from
'echarts/renderers'
import
{
ProductCategoryApi
,
IotStatisticsSummaryRespVO
,
IotStatisticsDeviceMessageSummaryRespVO
}
from
'@/api/iot/statistics'
import
{
IotStatisticsDeviceMessageSummaryRespVO
,
IotStatisticsSummaryRespVO
,
ProductCategoryApi
}
from
'@/api/iot/statistics'
import
{
formatDate
}
from
'@/utils/formatTime'
import
{
formatDate
}
from
'@/utils/formatTime'
import
{
Icon
}
from
'@/components/Icon'
/** IoT 首页 */
defineOptions
({
name
:
'IotHome'
})
const
timeRange
=
ref
(
'7d'
)
// 修改默认选择为近一周
// TODO @super:参考下 /Users/yunai/Java/yudao-ui-admin-vue3/src/views/mall/home/index.vue,拆一拆组件
const
dateRange
=
ref
<
[
Date
,
Date
]
|
null
>
(
null
)
const
queryParams
=
reactive
({
/** IoT 首页 */
startTime
:
Date
.
now
()
-
7
*
24
*
60
*
60
*
1000
,
// 设置默认开始时间为7天前
defineOptions
({
name
:
'IoTHome'
})
endTime
:
Date
.
now
()
// 设置默认结束时间为当前时间
})
// TODO @super:使用下 Echart 组件,参考 yudao-ui-admin-vue3/src/views/mall/home/components/TradeTrendCard.vue 等
echarts
.
use
([
echarts
.
use
([
TooltipComponent
,
TooltipComponent
,
LegendComponent
,
LegendComponent
,
...
@@ -181,14 +186,22 @@ echarts.use([
...
@@ -181,14 +186,22 @@ echarts.use([
GaugeChart
GaugeChart
])
])
const
chartDeviceNumStat
=
ref
()
const
timeRange
=
ref
(
'7d'
)
// 修改默认选择为近一周
const
chartDeviceOnline
=
ref
()
const
dateRange
=
ref
<
[
Date
,
Date
]
|
null
>
(
null
)
const
chartDeviceOffline
=
ref
()
const
chartDeviceActive
=
ref
()
const
chartMsgStat
=
ref
()
const
queryParams
=
reactive
({
startTime
:
Date
.
now
()
-
7
*
24
*
60
*
60
*
1000
,
// 设置默认开始时间为 7 天前
endTime
:
Date
.
now
()
// 设置默认结束时间为当前时间
})
const
deviceCountChartRef
=
ref
()
// 设备数量统计的图表
const
deviceOnlineCountChartRef
=
ref
()
// 在线设备统计的图表
const
deviceOfflineChartRef
=
ref
()
// 离线设备统计的图表
const
deviceActiveChartRef
=
ref
()
// 待激活设备统计的图表
const
deviceMessageCountChartRef
=
ref
()
// 上下行消息量统计的图表
// 基础统计数据
// 基础统计数据
// TODO @super:初始为 -1,然后界面展示先是加载中?试试用 cursor 改哈
const
statsData
=
ref
<
IotStatisticsSummaryRespVO
>
({
const
statsData
=
ref
<
IotStatisticsSummaryRespVO
>
({
productCategoryCount
:
0
,
productCategoryCount
:
0
,
productCount
:
0
,
productCount
:
0
,
...
@@ -211,11 +224,12 @@ const messageStats = ref<IotStatisticsDeviceMessageSummaryRespVO>({
...
@@ -211,11 +224,12 @@ const messageStats = ref<IotStatisticsDeviceMessageSummaryRespVO>({
})
})
/** 处理快捷时间范围选择 */
/** 处理快捷时间范围选择 */
const
handleTimeRangeChange
=
(
valu
e
:
string
)
=>
{
const
handleTimeRangeChange
=
(
timeRang
e
:
string
)
=>
{
const
now
=
Date
.
now
()
const
now
=
Date
.
now
()
let
startTime
:
number
let
startTime
:
number
switch
(
value
)
{
// TODO @super:这个的计算,看看能不能结合 dayjs 简化。因为 1h、24h、7d 感觉是比较标准的。如果没有,抽到 utils/formatTime.ts 作为一个工具方法
switch
(
timeRange
)
{
case
'1h'
:
case
'1h'
:
startTime
=
now
-
60
*
60
*
1000
startTime
=
now
-
60
*
60
*
1000
break
break
...
@@ -258,12 +272,10 @@ const handleDateRangeChange = (value: [Date, Date] | null) => {
...
@@ -258,12 +272,10 @@ const handleDateRangeChange = (value: [Date, Date] | null) => {
/** 获取统计数据 */
/** 获取统计数据 */
const
getStats
=
async
()
=>
{
const
getStats
=
async
()
=>
{
// 获取基础统计数据
// 获取基础统计数据
const
summaryRes
=
await
ProductCategoryApi
.
getIotStatisticsSummary
()
statsData
.
value
=
await
ProductCategoryApi
.
getIotStatisticsSummary
()
statsData
.
value
=
summaryRes
// 获取消息统计数据
// 获取消息统计数据
const
messageRes
=
await
ProductCategoryApi
.
getIotStatisticsDeviceMessageSummary
(
queryParams
)
messageStats
.
value
=
await
ProductCategoryApi
.
getIotStatisticsDeviceMessageSummary
(
queryParams
)
messageStats
.
value
=
messageRes
// 初始化图表
// 初始化图表
initCharts
()
initCharts
()
...
@@ -272,7 +284,7 @@ const getStats = async () => {
...
@@ -272,7 +284,7 @@ const getStats = async () => {
/** 初始化图表 */
/** 初始化图表 */
const
initCharts
=
()
=>
{
const
initCharts
=
()
=>
{
// 设备数量统计
// 设备数量统计
echarts
.
init
(
chartDeviceNumStat
.
value
).
setOption
({
echarts
.
init
(
deviceCountChartRef
.
value
).
setOption
({
tooltip
:
{
tooltip
:
{
trigger
:
'item'
trigger
:
'item'
},
},
...
@@ -313,13 +325,11 @@ const initCharts = () => {
...
@@ -313,13 +325,11 @@ const initCharts = () => {
})
})
// 在线设备统计
// 在线设备统计
initGaugeChart
(
chartDeviceOnline
.
value
,
statsData
.
value
.
deviceOnlineCount
,
'#0d9'
)
initGaugeChart
(
deviceOnlineCountChartRef
.
value
,
statsData
.
value
.
deviceOnlineCount
,
'#0d9'
)
// 离线设备统计
// 离线设备统计
initGaugeChart
(
chartDeviceOffline
.
value
,
statsData
.
value
.
deviceOfflineCount
,
'#f50'
)
initGaugeChart
(
deviceOfflineChartRef
.
value
,
statsData
.
value
.
deviceOfflineCount
,
'#f50'
)
// 待激活设备统计
// 待激活设备统计
initGaugeChart
(
chartDeviceActive
.
value
,
statsData
.
value
.
deviceInactiveCount
,
'#05b'
)
initGaugeChart
(
deviceActiveChartRef
.
value
,
statsData
.
value
.
deviceInactiveCount
,
'#05b'
)
// 消息量统计
// 消息量统计
initMessageChart
()
initMessageChart
()
...
@@ -362,7 +372,7 @@ const initGaugeChart = (el: any, value: number, color: string) => {
...
@@ -362,7 +372,7 @@ const initGaugeChart = (el: any, value: number, color: string) => {
color
:
color
,
color
:
color
,
offsetCenter
:
[
0
,
'0'
],
offsetCenter
:
[
0
,
'0'
],
formatter
:
(
value
:
number
)
=>
{
formatter
:
(
value
:
number
)
=>
{
return
`
${
value
}
个`
return
`
${
value
}
个`
}
}
},
},
data
:
[{
value
:
value
}]
data
:
[{
value
:
value
}]
...
@@ -374,30 +384,31 @@ const initGaugeChart = (el: any, value: number, color: string) => {
...
@@ -374,30 +384,31 @@ const initGaugeChart = (el: any, value: number, color: string) => {
/** 初始化消息统计图表 */
/** 初始化消息统计图表 */
const
initMessageChart
=
()
=>
{
const
initMessageChart
=
()
=>
{
// 获取所有时间戳并排序
// 获取所有时间戳并排序
// TODO @super:一些 idea 里的红色报错,要去处理掉噢。
const
timestamps
=
Array
.
from
(
const
timestamps
=
Array
.
from
(
new
Set
([
new
Set
([
...
messageStats
.
value
.
upstreamCounts
.
map
(
item
=>
Number
(
Object
.
keys
(
item
)[
0
])),
...
messageStats
.
value
.
upstreamCounts
.
map
(
(
item
)
=>
Number
(
Object
.
keys
(
item
)[
0
])),
...
messageStats
.
value
.
downstreamCounts
.
map
(
item
=>
Number
(
Object
.
keys
(
item
)[
0
]))
...
messageStats
.
value
.
downstreamCounts
.
map
(
(
item
)
=>
Number
(
Object
.
keys
(
item
)[
0
]))
])
])
).
sort
((
a
,
b
)
=>
a
-
b
)
// 确保时间戳从小到大排序
).
sort
((
a
,
b
)
=>
a
-
b
)
// 确保时间戳从小到大排序
// 准备数据
// 准备数据
const
xdata
=
timestamps
.
map
(
ts
=>
formatDate
(
ts
,
'YYYY-MM-DD HH:mm'
))
const
xdata
=
timestamps
.
map
(
(
ts
)
=>
formatDate
(
ts
,
'YYYY-MM-DD HH:mm'
))
const
upData
=
timestamps
.
map
(
ts
=>
{
const
upData
=
timestamps
.
map
(
(
ts
)
=>
{
const
item
=
messageStats
.
value
.
upstreamCounts
.
find
(
const
item
=
messageStats
.
value
.
upstreamCounts
.
find
(
count
=>
Number
(
Object
.
keys
(
count
)[
0
])
===
ts
(
count
)
=>
Number
(
Object
.
keys
(
count
)[
0
])
===
ts
)
)
return
item
?
Object
.
values
(
item
)[
0
]
:
0
return
item
?
Object
.
values
(
item
)[
0
]
:
0
})
})
const
downData
=
timestamps
.
map
(
ts
=>
{
const
downData
=
timestamps
.
map
(
(
ts
)
=>
{
const
item
=
messageStats
.
value
.
downstreamCounts
.
find
(
const
item
=
messageStats
.
value
.
downstreamCounts
.
find
(
count
=>
Number
(
Object
.
keys
(
count
)[
0
])
===
ts
(
count
)
=>
Number
(
Object
.
keys
(
count
)[
0
])
===
ts
)
)
return
item
?
Object
.
values
(
item
)[
0
]
:
0
return
item
?
Object
.
values
(
item
)[
0
]
:
0
})
})
// 配置图表
// 配置图表
echarts
.
init
(
chartMsgStat
.
value
).
setOption
({
echarts
.
init
(
deviceMessageCountChartRef
.
value
).
setOption
({
tooltip
:
{
tooltip
:
{
trigger
:
'axis'
,
trigger
:
'axis'
,
backgroundColor
:
'rgba(255, 255, 255, 0.9)'
,
backgroundColor
:
'rgba(255, 255, 255, 0.9)'
,
...
@@ -491,59 +502,8 @@ const initMessageChart = () => {
...
@@ -491,59 +502,8 @@ const initMessageChart = () => {
/** 初始化 */
/** 初始化 */
onMounted
(()
=>
{
onMounted
(()
=>
{
if
(
document
.
getElementById
(
'breadcrumb-container'
))
{
document
.
getElementById
(
'breadcrumb-container'
)
!
.
style
.
display
=
'none'
}
getStats
()
getStats
()
})
})
</
script
>
</
script
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
></
style
>
.stat-card
{
@apply
bg-white
rounded
overflow-hidden;
:deep(.el-card__body)
{
@apply
p-3;
}
.el-divider
{
@apply
my-2;
}
}
.chart-card
{
@apply
bg-white
rounded
overflow-hidden;
:deep(.el-card__header)
{
@apply
py-2
px-3
border-b
border-gray-100
bg-white;
}
:deep
(
.el-card__body
)
{
@apply
p-3;
}
}
//
修改图表配色方案,使其更加柔和
:deep
(
.echarts
)
{
.tooltip
{
@apply
bg-white/90
border
border-gray-200
shadow-sm;
}
.axis-line
{
@apply
text-gray-300;
}
.split-line
{
@apply
text-gray-100;
}
}
//
添加时间选择器样式
:deep
(
.el-radio-group
)
{
@apply
mr-4;
}
:deep
(
.el-date-editor
)
{
@apply
w-[360px];
}
</
style
>
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