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
Unverified
Commit
c4e5419d
authored
Mar 28, 2023
by
芋道源码
Committed by
Gitee
Mar 28, 2023
Browse files
Options
Browse Files
Download
Plain Diff
!69 Vue3重构:公众号统计
Merge pull request !69 from kinlon92/dev
parents
d7891fe7
51344a59
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
482 additions
and
1 deletions
+482
-1
src/utils/dateUtils.ts
+79
-0
src/views/mp/statistics/index.vue
+403
-1
No files found.
src/utils/dateUtils.ts
0 → 100644
View file @
c4e5419d
/**
* 将毫秒,转换成时间字符串。例如说,xx 分钟
*
* @param ms 毫秒
* @returns {string} 字符串
*/
export
function
getDate
(
ms
)
{
const
day
=
Math
.
floor
(
ms
/
(
24
*
60
*
60
*
1000
))
const
hour
=
Math
.
floor
(
ms
/
(
60
*
60
*
1000
)
-
day
*
24
)
const
minute
=
Math
.
floor
(
ms
/
(
60
*
1000
)
-
day
*
24
*
60
-
hour
*
60
)
const
second
=
Math
.
floor
(
ms
/
1000
-
day
*
24
*
60
*
60
-
hour
*
60
*
60
-
minute
*
60
)
if
(
day
>
0
)
{
return
day
+
'天'
+
hour
+
'小时'
+
minute
+
'分钟'
}
if
(
hour
>
0
)
{
return
hour
+
'小时'
+
minute
+
'分钟'
}
if
(
minute
>
0
)
{
return
minute
+
'分钟'
}
if
(
second
>
0
)
{
return
second
+
'秒'
}
else
{
return
0
+
'秒'
}
}
export
function
beginOfDay
(
date
)
{
return
new
Date
(
date
.
getFullYear
(),
date
.
getMonth
(),
date
.
getDate
())
}
export
function
endOfDay
(
date
)
{
return
new
Date
(
date
.
getFullYear
(),
date
.
getMonth
(),
date
.
getDate
(),
23
,
59
,
59
,
999
)
}
export
function
betweenDay
(
date1
,
date2
)
{
date1
=
convertDate
(
date1
)
date2
=
convertDate
(
date2
)
// 计算差值
return
Math
.
floor
((
date2
.
getTime
()
-
date1
.
getTime
())
/
(
24
*
3600
*
1000
))
}
export
function
formatDate
(
date
,
fmt
)
{
date
=
convertDate
(
date
)
const
o
=
{
'M+'
:
date
.
getMonth
()
+
1
,
//月份
'd+'
:
date
.
getDate
(),
//日
'H+'
:
date
.
getHours
(),
//小时
'm+'
:
date
.
getMinutes
(),
//分
's+'
:
date
.
getSeconds
(),
//秒
'q+'
:
Math
.
floor
((
date
.
getMonth
()
+
3
)
/
3
),
//季度
S
:
date
.
getMilliseconds
()
//毫秒
}
if
(
/
(
y+
)
/
.
test
(
fmt
))
{
// 年份
fmt
=
fmt
.
replace
(
RegExp
.
$1
,
(
date
.
getFullYear
()
+
''
).
substr
(
4
-
RegExp
.
$1
.
length
))
}
for
(
const
k
in
o
)
{
if
(
new
RegExp
(
'('
+
k
+
')'
).
test
(
fmt
))
{
fmt
=
fmt
.
replace
(
RegExp
.
$1
,
RegExp
.
$1
.
length
===
1
?
o
[
k
]
:
(
'00'
+
o
[
k
]).
substr
((
''
+
o
[
k
]).
length
)
)
}
}
return
fmt
}
export
function
addTime
(
date
,
time
)
{
date
=
convertDate
(
date
)
return
new
Date
(
date
.
getTime
()
+
time
)
}
export
function
convertDate
(
date
)
{
if
(
typeof
date
===
'string'
)
{
return
new
Date
(
date
)
}
return
date
}
src/views/mp/statistics/index.vue
View file @
c4e5419d
<
template
>
<
template
>
<span>
开发中
</span>
<!-- 搜索工作栏 -->
<content-wrap>
<el-form
ref=
"queryForm"
class=
"-mb-15px"
:inline=
"true"
label-width=
"68px"
>
<el-form-item
label=
"公众号"
prop=
"accountId"
>
<el-select
v-model=
"accountId"
@
change=
"getSummary"
>
<el-option
v-for=
"item in accounts"
:key=
"parseInt(item.id)"
:label=
"item.name"
:value=
"parseInt(item.id)"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"时间范围"
prop=
"dateRange"
>
<el-date-picker
v-model=
"dateRange"
style=
"width: 260px"
type=
"daterange"
range-separator=
"-"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
:default-time=
"defaultTime"
@
change=
"getSummary"
/>
</el-form-item>
</el-form>
</content-wrap>
<!-- 图表 -->
<content-wrap>
<el-row>
<el-col
:span=
"12"
class=
"card-box"
>
<el-card>
<template
#
header
>
<div>
<span>
用户增减数据
</span>
</div>
</
template
>
<div
class=
"el-table el-table--enable-row-hover el-table--medium"
>
<div
ref=
"userSummaryChartRef"
style=
"height: 420px"
></div>
</div>
</el-card>
</el-col>
<el-col
:span=
"12"
class=
"card-box"
>
<el-card>
<
template
#
header
>
<div>
<span>
累计用户数据
</span>
</div>
</
template
>
<div
class=
"el-table el-table--enable-row-hover el-table--medium"
>
<div
ref=
"userCumulateChartRef"
style=
"height: 420px"
></div>
</div>
</el-card>
</el-col>
<el-col
:span=
"12"
class=
"card-box"
>
<el-card>
<
template
#
header
>
<div>
<span>
消息概况数据
</span>
</div>
</
template
>
<div
class=
"el-table el-table--enable-row-hover el-table--medium"
>
<div
ref=
"upstreamMessageChartRef"
style=
"height: 420px"
></div>
</div>
</el-card>
</el-col>
<el-col
:span=
"12"
class=
"card-box"
>
<el-card>
<
template
#
header
>
<div>
<span>
接口分析数据
</span>
</div>
</
template
>
<div
class=
"el-table el-table--enable-row-hover el-table--medium"
>
<div
ref=
"interfaceSummaryChartRef"
style=
"height: 420px"
></div>
</div>
</el-card>
</el-col>
</el-row>
</content-wrap>
</template>
</template>
<
script
setup
lang=
"ts"
name=
"MpStatistics"
>
// 引入基本模板
import
*
as
echarts
from
'echarts'
import
{
getInterfaceSummary
,
getUpstreamMessage
,
getUserCumulate
,
getUserSummary
}
from
'@/api/mp/statistics'
import
{
addTime
,
beginOfDay
,
betweenDay
,
endOfDay
,
formatDate
}
from
'@/utils/dateUtils'
import
{
getSimpleAccountList
}
from
'@/api/mp/account'
const
message
=
useMessage
()
// 消息弹窗
const
defaultTime
=
ref
<
[
Date
,
Date
]
>
([
new
Date
(
2000
,
1
,
1
,
0
,
0
,
0
),
new
Date
(
2000
,
2
,
1
,
23
,
59
,
59
)
])
const
dateRange
=
ref
([
beginOfDay
(
new
Date
(
new
Date
().
getTime
()
-
3600
*
1000
*
24
*
7
)),
endOfDay
(
new
Date
(
new
Date
().
getTime
()
-
3600
*
1000
*
24
))
])
// -1 天
const
accountId
=
ref
()
const
accounts
=
ref
([
{
id
:
'0'
,
name
:
''
}
])
const
userSummaryChartRef
=
ref
()
const
userCumulateChartRef
=
ref
()
const
upstreamMessageChartRef
=
ref
()
const
interfaceSummaryChartRef
=
ref
()
const
xAxisDate
=
ref
([]
as
any
[])
// X 轴的日期范围
const
userSummaryOption
=
reactive
({
// 用户增减数据
color
:
[
'#67C23A'
,
'#e5323e'
],
legend
:
{
data
:
[
'新增用户'
,
'取消关注的用户'
]
},
tooltip
:
{},
xAxis
:
{
data
:
[]
as
any
[]
// X 轴的日期范围
},
yAxis
:
{
minInterval
:
1
},
series
:
[
{
name
:
'新增用户'
,
type
:
'bar'
,
label
:
{
show
:
true
},
barGap
:
0
,
data
:
[]
as
any
[]
// 新增用户的数据
},
{
name
:
'取消关注的用户'
,
type
:
'bar'
,
label
:
{
show
:
true
},
data
:
[]
as
any
[]
// 取消关注的用户的数据
}
]
})
const
userCumulateOption
=
reactive
({
// 累计用户数据
legend
:
{
data
:
[
'累计用户量'
]
},
xAxis
:
{
type
:
'category'
,
data
:
[]
as
any
[]
},
yAxis
:
{
minInterval
:
1
},
series
:
[
{
name
:
'累计用户量'
,
data
:
[]
as
any
[],
// 累计用户量的数据
type
:
'line'
,
smooth
:
true
,
label
:
{
show
:
true
}
}
]
})
const
upstreamMessageOption
=
reactive
({
// 消息发送概况数据
color
:
[
'#67C23A'
,
'#e5323e'
],
legend
:
{
data
:
[
'用户发送人数'
,
'用户发送条数'
]
},
tooltip
:
{},
xAxis
:
{
data
:
[]
as
any
[]
// X 轴的日期范围
},
yAxis
:
{
minInterval
:
1
},
series
:
[
{
name
:
'用户发送人数'
,
type
:
'line'
,
smooth
:
true
,
label
:
{
show
:
true
},
data
:
[]
as
any
[]
// 用户发送人数的数据
},
{
name
:
'用户发送条数'
,
type
:
'line'
,
smooth
:
true
,
label
:
{
show
:
true
},
data
:
[]
as
any
[]
// 用户发送条数的数据
}
]
})
const
interfaceSummaryOption
=
reactive
({
// 接口分析况数据
color
:
[
'#67C23A'
,
'#e5323e'
,
'#E6A23C'
,
'#409EFF'
],
legend
:
{
data
:
[
'被动回复用户消息的次数'
,
'失败次数'
,
'最大耗时'
,
'总耗时'
]
},
tooltip
:
{},
xAxis
:
{
data
:
[]
as
any
[]
// X 轴的日期范围
},
yAxis
:
{},
series
:
[
{
name
:
'被动回复用户消息的次数'
,
type
:
'bar'
,
label
:
{
show
:
true
},
barGap
:
0
,
data
:
[]
as
any
[]
// 被动回复用户消息的次数的数据
},
{
name
:
'失败次数'
,
type
:
'bar'
,
label
:
{
show
:
true
},
data
:
[]
as
any
[]
// 失败次数的数据
},
{
name
:
'最大耗时'
,
type
:
'bar'
,
label
:
{
show
:
true
},
data
:
[]
as
any
[]
// 最大耗时的数据
},
{
name
:
'总耗时'
,
type
:
'bar'
,
label
:
{
show
:
true
},
data
:
[]
as
any
[]
// 总耗时的数据
}
]
})
onMounted
(
async
()
=>
{
// 获取公众号下拉列表
await
getAccountList
()
// 加载数据
getSummary
()
})
const
getAccountList
=
async
()
=>
{
const
data
=
await
getSimpleAccountList
()
accounts
.
value
=
data
// 默认选中第一个
if
(
accounts
.
value
.
length
>
0
)
{
accountId
.
value
=
accounts
.
value
[
0
].
id
}
}
const
getSummary
=
()
=>
{
// 如果没有选中公众号账号,则进行提示。
if
(
!
accountId
)
{
message
.
error
(
'未选中公众号,无法统计数据'
)
return
false
}
// 必须选择 7 天内,因为公众号有时间跨度限制为 7
if
(
betweenDay
(
dateRange
.
value
[
0
],
dateRange
.
value
[
1
])
>=
7
)
{
message
.
error
(
'时间间隔 7 天以内,请重新选择'
)
return
false
}
xAxisDate
.
value
=
[]
const
days
=
betweenDay
(
dateRange
.
value
[
0
],
dateRange
.
value
[
1
])
// 相差天数
for
(
let
i
=
0
;
i
<=
days
;
i
++
)
{
xAxisDate
.
value
.
push
(
formatDate
(
addTime
(
dateRange
.
value
[
0
],
3600
*
1000
*
24
*
i
),
'yyyy-MM-dd'
)
)
}
// 初始化图表
initUserSummaryChart
()
initUserCumulateChart
()
initUpstreamMessageChart
()
interfaceSummaryChart
()
}
const
initUserSummaryChart
=
async
()
=>
{
userSummaryOption
.
xAxis
.
data
=
[]
userSummaryOption
.
series
[
0
].
data
=
[]
userSummaryOption
.
series
[
1
].
data
=
[]
try
{
const
data
=
await
getUserSummary
({
accountId
:
accountId
.
value
,
date
:
[
formatDate
(
dateRange
.
value
[
0
],
'yyyy-MM-dd HH:mm:ss'
),
formatDate
(
dateRange
.
value
[
1
],
'yyyy-MM-dd HH:mm:ss'
)
]
})
userSummaryOption
.
xAxis
.
data
=
xAxisDate
.
value
// 处理数据
xAxisDate
.
value
.
forEach
((
date
,
index
)
=>
{
data
.
forEach
((
item
)
=>
{
// 匹配日期
const
refDate
=
formatDate
(
new
Date
(
item
.
refDate
),
'yyyy-MM-dd'
)
if
(
refDate
.
indexOf
(
date
)
===
-
1
)
{
return
}
// 设置数据到对应的位置
userSummaryOption
.
series
[
0
].
data
[
index
]
=
item
.
newUser
userSummaryOption
.
series
[
1
].
data
[
index
]
=
item
.
cancelUser
})
})
// 绘制图表
const
userSummaryChart
=
echarts
.
init
(
userSummaryChartRef
.
value
)
userSummaryChart
.
setOption
(
userSummaryOption
)
}
catch
{}
}
const
initUserCumulateChart
=
async
()
=>
{
userCumulateOption
.
xAxis
.
data
=
[]
userCumulateOption
.
series
[
0
].
data
=
[]
// 发起请求
try
{
const
data
=
await
getUserCumulate
({
accountId
:
accountId
.
value
,
date
:
[
formatDate
(
dateRange
.
value
[
0
],
'yyyy-MM-dd HH:mm:ss'
),
formatDate
(
dateRange
.
value
[
1
],
'yyyy-MM-dd HH:mm:ss'
)
]
})
userCumulateOption
.
xAxis
.
data
=
xAxisDate
.
value
// 处理数据
data
.
forEach
((
item
,
index
)
=>
{
userCumulateOption
.
series
[
0
].
data
[
index
]
=
item
.
cumulateUser
})
// 绘制图表
const
userCumulateChart
=
echarts
.
init
(
userCumulateChartRef
.
value
)
userCumulateChart
.
setOption
(
userCumulateOption
)
}
catch
{}
}
const
initUpstreamMessageChart
=
async
()
=>
{
upstreamMessageOption
.
xAxis
.
data
=
[]
upstreamMessageOption
.
series
[
0
].
data
=
[]
upstreamMessageOption
.
series
[
1
].
data
=
[]
// 发起请求
try
{
const
data
=
await
getUpstreamMessage
({
accountId
:
accountId
.
value
,
date
:
[
formatDate
(
dateRange
.
value
[
0
],
'yyyy-MM-dd HH:mm:ss'
),
formatDate
(
dateRange
.
value
[
1
],
'yyyy-MM-dd HH:mm:ss'
)
]
})
upstreamMessageOption
.
xAxis
.
data
=
xAxisDate
.
value
// 处理数据
data
.
forEach
((
item
,
index
)
=>
{
upstreamMessageOption
.
series
[
0
].
data
[
index
]
=
item
.
messageUser
upstreamMessageOption
.
series
[
1
].
data
[
index
]
=
item
.
messageCount
})
// 绘制图表
const
upstreamMessageChart
=
echarts
.
init
(
upstreamMessageChartRef
.
value
)
upstreamMessageChart
.
setOption
(
upstreamMessageOption
)
}
catch
{}
}
const
interfaceSummaryChart
=
async
()
=>
{
interfaceSummaryOption
.
xAxis
.
data
=
[]
interfaceSummaryOption
.
series
[
0
].
data
=
[]
interfaceSummaryOption
.
series
[
1
].
data
=
[]
interfaceSummaryOption
.
series
[
2
].
data
=
[]
interfaceSummaryOption
.
series
[
3
].
data
=
[]
// 发起请求
try
{
const
data
=
await
getInterfaceSummary
({
accountId
:
accountId
.
value
,
date
:
[
formatDate
(
dateRange
.
value
[
0
],
'yyyy-MM-dd HH:mm:ss'
),
formatDate
(
dateRange
.
value
[
1
],
'yyyy-MM-dd HH:mm:ss'
)
]
})
interfaceSummaryOption
.
xAxis
.
data
=
xAxisDate
.
value
// 处理数据
data
.
forEach
((
item
,
index
)
=>
{
interfaceSummaryOption
.
series
[
0
].
data
[
index
]
=
item
.
callbackCount
interfaceSummaryOption
.
series
[
1
].
data
[
index
]
=
item
.
failCount
interfaceSummaryOption
.
series
[
2
].
data
[
index
]
=
item
.
maxTimeCost
interfaceSummaryOption
.
series
[
3
].
data
[
index
]
=
item
.
totalTimeCost
})
// 绘制图表
const
interfaceSummaryChart
=
echarts
.
init
(
interfaceSummaryChartRef
.
value
)
interfaceSummaryChart
.
setOption
(
interfaceSummaryOption
)
}
catch
{}
}
</
script
>
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