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
f848f3ba
authored
Apr 22, 2023
by
dhb52
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: mp/wx-msg 拆分组件
parent
917b9d18
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
207 additions
and
179 deletions
+207
-179
src/views/mp/components/wx-msg/components/MsgEvent.vue
+51
-0
src/views/mp/components/wx-msg/components/MsgList.vue
+110
-0
src/views/mp/components/wx-msg/main.vue
+40
-179
src/views/mp/components/wx-msg/types.ts
+6
-0
No files found.
src/views/mp/components/wx-msg/components/MsgEvent.vue
0 → 100644
View file @
f848f3ba
<
template
>
<div>
<div
v-if=
"item.event === 'subscribe'"
>
<el-tag
type=
"success"
>
关注
</el-tag>
</div>
<div
v-else-if=
"item.event === 'unsubscribe'"
>
<el-tag
type=
"danger"
>
取消关注
</el-tag>
</div>
<div
v-else-if=
"item.event === 'CLICK'"
>
<el-tag>
点击菜单
</el-tag>
【
{{
item
.
eventKey
}}
】
</div>
<div
v-else-if=
"item.event === 'VIEW'"
>
<el-tag>
点击菜单链接
</el-tag>
【
{{
item
.
eventKey
}}
】
</div>
<div
v-else-if=
"item.event === 'scancode_waitmsg'"
>
<el-tag>
扫码结果
</el-tag>
【
{{
item
.
eventKey
}}
】
</div>
<div
v-else-if=
"item.event === 'scancode_push'"
>
<el-tag>
扫码结果
</el-tag>
【
{{
item
.
eventKey
}}
】
</div>
<div
v-else-if=
"item.event === 'pic_sysphoto'"
>
<el-tag>
系统拍照发图
</el-tag>
</div>
<div
v-else-if=
"item.event === 'pic_photo_or_album'"
>
<el-tag>
拍照或者相册
</el-tag>
</div>
<div
v-else-if=
"item.event === 'pic_weixin'"
>
<el-tag>
微信相册
</el-tag>
</div>
<div
v-else-if=
"item.event === 'location_select'"
>
<el-tag>
选择地理位置
</el-tag>
</div>
<div
v-else
>
<el-tag
type=
"danger"
>
未知事件类型
</el-tag>
</div>
</div>
</
template
>
<
script
setup
lang=
"ts"
>
const
props
=
defineProps
<
{
item
:
any
}
>
()
const
item
=
ref
(
props
.
item
)
</
script
>
<
style
scoped
></
style
>
src/views/mp/components/wx-msg/components/MsgList.vue
0 → 100644
View file @
f848f3ba
<
template
>
<div
class=
"execution"
v-for=
"item in props.list"
:key=
"item.id"
>
<div
class=
"avue-comment"
:class=
"
{ 'avue-comment--reverse': item.sendFrom === SendFrom.MpBot }"
>
<div
class=
"avatar-div"
>
<img
:src=
"getAvatar(item.sendFrom)"
class=
"avue-comment__avatar"
/>
<div
class=
"avue-comment__author"
>
{{
getNickname
(
item
.
sendFrom
)
}}
</div>
</div>
<div
class=
"avue-comment__main"
>
<div
class=
"avue-comment__header"
>
<div
class=
"avue-comment__create_time"
>
{{
formatDate
(
item
.
createTime
)
}}
</div>
</div>
<div
class=
"avue-comment__body"
:style=
"item.sendFrom === SendFrom.MpBot ? 'background: #6BED72;' : ''"
>
<!-- 【事件】区域 -->
<MsgEvent
v-if=
"item.type === MsgType.Event"
:item=
"item"
/>
<!-- 【消息】区域 -->
<div
v-else-if=
"item.type === MsgType.Text"
>
{{
item
.
content
}}
</div>
<div
v-else-if=
"item.type === MsgType.Voice"
>
<WxVoicePlayer
:url=
"item.mediaUrl"
:content=
"item.recognition"
/>
</div>
<div
v-else-if=
"item.type === MsgType.Image"
>
<a
target=
"_blank"
:href=
"item.mediaUrl"
>
<img
:src=
"item.mediaUrl"
style=
"width: 100px"
/>
</a>
</div>
<div
v-else-if=
"item.type === MsgType.Video || item.type === 'shortvideo'"
style=
"text-align: center"
>
<WxVideoPlayer
:url=
"item.mediaUrl"
/>
</div>
<div
v-else-if=
"item.type === MsgType.Link"
class=
"avue-card__detail"
>
<el-link
type=
"success"
:underline=
"false"
target=
"_blank"
:href=
"item.url"
>
<div
class=
"avue-card__title"
><i
class=
"el-icon-link"
></i>
{{
item
.
title
}}
</div>
</el-link>
<div
class=
"avue-card__info"
style=
"height: unset"
>
{{
item
.
description
}}
</div>
</div>
<!-- TODO 芋艿:待完善 -->
<div
v-else-if=
"item.type === MsgType.Location"
>
<WxLocation
:label=
"item.label"
:location-y=
"item.locationY"
:location-x=
"item.locationX"
/>
</div>
<div
v-else-if=
"item.type === MsgType.News"
style=
"width: 300px"
>
<!-- TODO 芋艿:待测试;详情页也存在类似的情况 -->
<WxNews
:articles=
"item.articles"
/>
</div>
<div
v-else-if=
"item.type === MsgType.Music"
>
<WxMusic
:title=
"item.title"
:description=
"item.description"
:thumb-media-url=
"item.thumbMediaUrl"
:music-url=
"item.musicUrl"
:hq-music-url=
"item.hqMusicUrl"
/>
</div>
</div>
</div>
</div>
</div>
</
template
>
<
script
setup
lang=
"ts"
name=
"MsgList"
>
import
WxVideoPlayer
from
'@/views/mp/components/wx-video-play'
import
WxVoicePlayer
from
'@/views/mp/components/wx-voice-play'
import
WxNews
from
'@/views/mp/components/wx-news'
import
WxLocation
from
'@/views/mp/components/wx-location'
import
WxMusic
from
'@/views/mp/components/wx-music'
import
MsgEvent
from
'./MsgEvent.vue'
import
{
formatDate
}
from
'@/utils/formatTime'
import
{
MsgType
,
User
}
from
'../types'
import
avatarWechat
from
'@/assets/imgs/wechat.png'
const
props
=
defineProps
<
{
list
:
any
[]
accountId
:
number
user
:
User
}
>
()
enum
SendFrom
{
User
=
1
,
MpBot
=
2
}
const
getAvatar
=
(
sendFrom
:
SendFrom
)
=>
sendFrom
===
SendFrom
.
User
?
props
.
user
.
avatar
:
avatarWechat
const
getNickname
=
(
sendFrom
:
SendFrom
)
=>
sendFrom
===
SendFrom
.
User
?
props
.
user
.
nickname
:
'公众号'
</
script
>
<
style
lang=
"scss"
scoped
>
/* 因为 joolun 实现依赖 avue 组件,该页面使用了 comment.scss、card.scc */
@import
'../comment.scss'
;
@import
'../card.scss'
;
.avatar-div
{
text-align
:
center
;
width
:
80px
;
}
</
style
>
src/views/mp/components/wx-msg/main.vue
View file @
f848f3ba
...
...
@@ -7,123 +7,22 @@
-->
<
template
>
<ContentWrap>
<div
class=
"msg-div"
:id=
"
'msg-div' + nowStr
"
>
<div
class=
"msg-div"
:id=
"
msgDivId
"
>
<!-- 加载更多 -->
<div
v-loading=
"loading"
></div>
<div
v-if=
"!loading"
>
<div
class=
"el-table__empty-block"
v-if=
"
loadMore"
@
click=
"loading
More"
<div
class=
"el-table__empty-block"
v-if=
"
hasMore"
@
click=
"load
More"
><span
class=
"el-table__empty-text"
>
点击加载更多
</span></div
>
<div
class=
"el-table__empty-block"
v-if=
"!
load
More"
<div
class=
"el-table__empty-block"
v-if=
"!
has
More"
><span
class=
"el-table__empty-text"
>
没有更多了
</span></div
>
</div>
<!-- 消息列表 -->
<div
class=
"execution"
v-for=
"item in list"
:key=
"item.id"
>
<div
class=
"avue-comment"
:class=
"item.sendFrom === 2 ? 'avue-comment--reverse' : ''"
>
<div
class=
"avatar-div"
>
<img
:src=
"item.sendFrom === 1 ? user.avatar : mp.avatar"
class=
"avue-comment__avatar"
/>
<div
class=
"avue-comment__author"
>
{{
item
.
sendFrom
===
1
?
user
.
nickname
:
mp
.
nickname
}}
</div>
</div>
<div
class=
"avue-comment__main"
>
<div
class=
"avue-comment__header"
>
<div
class=
"avue-comment__create_time"
>
{{
formatDate
(
item
.
createTime
)
}}
</div>
</div>
<div
class=
"avue-comment__body"
:style=
"item.sendFrom === 2 ? 'background: #6BED72;' : ''"
>
<!-- 【事件】区域 -->
<div
v-if=
"item.type === MsgType.Event && item.event === 'subscribe'"
>
<el-tag
type=
"success"
>
关注
</el-tag>
</div>
<div
v-else-if=
"item.type === MsgType.Event && item.event === 'unsubscribe'"
>
<el-tag
type=
"danger"
>
取消关注
</el-tag>
</div>
<div
v-else-if=
"item.type === MsgType.Event && item.event === 'CLICK'"
>
<el-tag>
点击菜单
</el-tag>
【
{{
item
.
eventKey
}}
】
</div>
<div
v-else-if=
"item.type === MsgType.Event && item.event === 'VIEW'"
>
<el-tag>
点击菜单链接
</el-tag>
【
{{
item
.
eventKey
}}
】
</div>
<div
v-else-if=
"item.type === MsgType.Event && item.event === 'scancode_waitmsg'"
>
<el-tag>
扫码结果
</el-tag>
【
{{
item
.
eventKey
}}
】
</div>
<div
v-else-if=
"item.type === MsgType.Event && item.event === 'scancode_push'"
>
<el-tag>
扫码结果
</el-tag>
【
{{
item
.
eventKey
}}
】
</div>
<div
v-else-if=
"item.type === MsgType.Event && item.event === 'pic_sysphoto'"
>
<el-tag>
系统拍照发图
</el-tag>
</div>
<div
v-else-if=
"item.type === MsgType.Event && item.event === 'pic_photo_or_album'"
>
<el-tag>
拍照或者相册
</el-tag>
</div>
<div
v-else-if=
"item.type === MsgType.Event && item.event === 'pic_weixin'"
>
<el-tag>
微信相册
</el-tag>
</div>
<div
v-else-if=
"item.type === MsgType.Event && item.event === 'location_select'"
>
<el-tag>
选择地理位置
</el-tag>
</div>
<div
v-else-if=
"item.type === MsgType.Event"
>
<el-tag
type=
"danger"
>
未知事件类型
</el-tag>
</div>
<!-- 【消息】区域 -->
<div
v-else-if=
"item.type === MsgType.Text"
>
{{
item
.
content
}}
</div>
<div
v-else-if=
"item.type === MsgType.Voice"
>
<WxVoicePlayer
:url=
"item.mediaUrl"
:content=
"item.recognition"
/>
</div>
<div
v-else-if=
"item.type === MsgType.Image"
>
<a
target=
"_blank"
:href=
"item.mediaUrl"
>
<img
:src=
"item.mediaUrl"
style=
"width: 100px"
/>
</a>
</div>
<div
v-else-if=
"item.type === MsgType.Video || item.type === 'shortvideo'"
style=
"text-align: center"
>
<WxVideoPlayer
:url=
"item.mediaUrl"
/>
</div>
<div
v-else-if=
"item.type === MsgType.Link"
class=
"avue-card__detail"
>
<el-link
type=
"success"
:underline=
"false"
target=
"_blank"
:href=
"item.url"
>
<div
class=
"avue-card__title"
><i
class=
"el-icon-link"
></i>
{{
item
.
title
}}
</div>
</el-link>
<div
class=
"avue-card__info"
style=
"height: unset"
>
{{
item
.
description
}}
</div>
</div>
<!-- TODO 芋艿:待完善 -->
<div
v-else-if=
"item.type === MsgType.Location"
>
<WxLocation
:label=
"item.label"
:location-y=
"item.locationY"
:location-x=
"item.locationX"
/>
</div>
<div
v-else-if=
"item.type === MsgType.News"
style=
"width: 300px"
>
<!-- TODO 芋艿:待测试;详情页也存在类似的情况 -->
<WxNews
:articles=
"item.articles"
/>
</div>
<div
v-else-if=
"item.type === MsgType.Music"
>
<WxMusic
:title=
"item.title"
:description=
"item.description"
:thumb-media-url=
"item.thumbMediaUrl"
:music-url=
"item.musicUrl"
:hq-music-url=
"item.hqMusicUrl"
/>
</div>
</div>
</div>
</div>
</div>
<MsgList
:list=
"list"
:account-id=
"accountId"
:user=
"user"
/>
</div>
<div
class=
"msg-send"
v-loading=
"sendLoading"
>
<WxReplySelect
ref=
"replySelectRef"
v-model=
"reply"
/>
<el-button
type=
"success"
class=
"send-but"
@
click=
"sendMsg"
>
发送(S)
</el-button>
...
...
@@ -132,18 +31,12 @@
</
template
>
<
script
setup
lang=
"ts"
name=
"WxMsg"
>
import
WxReplySelect
from
'@/views/mp/components/wx-reply'
import
WxVideoPlayer
from
'@/views/mp/components/wx-video-play'
import
WxVoicePlayer
from
'@/views/mp/components/wx-voice-play'
import
WxNews
from
'@/views/mp/components/wx-news'
import
WxLocation
from
'@/views/mp/components/wx-location'
import
WxMusic
from
'@/views/mp/components/wx-music'
import
WxReplySelect
,
{
Reply
,
ReplyType
}
from
'@/views/mp/components/wx-reply'
import
MsgList
from
'./components/MsgList.vue'
import
{
getMessagePage
,
sendMessage
}
from
'@/api/mp/message'
import
{
getUser
}
from
'@/api/mp/user'
import
{
formatDate
}
from
'@/utils/formatTime'
import
profile
from
'@/assets/imgs/profile.jpg'
import
wechat
from
'@/assets/imgs/wechat.png'
import
{
MsgType
}
from
'./types'
import
{
User
}
from
'./types'
const
message
=
useMessage
()
// 消息弹窗
...
...
@@ -154,49 +47,30 @@ const props = defineProps({
}
})
const
nowStr
=
ref
(
new
Date
().
getTime
())
// 当前的时间戳,用于每次消息加载后,回到原位置;具体见 :id="'msg-div' + nowStr" 处
const
accountId
=
ref
<
number
>
(
-
1
)
// 公众号ID,需要通过userId初始化
const
msgDivId
=
`msg-div-{new Date().getTime()}`
// 当前的时间戳,用于每次消息加载后,回到原位置;具体见 :id="'msg-div' + nowStr" 处
const
loading
=
ref
(
false
)
// 消息列表是否正在加载中
const
load
More
=
ref
(
true
)
// 是否可以加载更多
const
has
More
=
ref
(
true
)
// 是否可以加载更多
const
list
=
ref
<
any
[]
>
([])
// 消息列表
const
queryParams
=
reactive
({
pageNo
:
1
,
// 当前页数
pageSize
:
14
,
// 每页显示多少条
accountId
:
undefine
d
accountId
:
accountI
d
})
interface
User
{
nickname
:
string
avatar
:
string
accountId
:
number
}
// 由于微信不再提供昵称,直接使用“用户”展示
const
user
:
User
=
reactive
({
nickname
:
'用户'
,
avatar
:
profile
,
accountId
:
0
// 公众号账号编号
})
interface
Mp
{
nickname
:
string
avatar
:
string
}
const
mp
:
Mp
=
reactive
({
nickname
:
'公众号'
,
avatar
:
wechat
accountId
:
accountId
// 公众号账号编号
})
// ========= 消息发送 =========
const
sendLoading
=
ref
(
false
)
// 发送消息是否加载中
interface
Reply
{
type
:
MsgType
accountId
:
number
|
null
articles
:
any
[]
}
// 微信发送消息
const
reply
=
ref
<
Reply
>
({
type
:
Msg
Type
.
Text
,
accountId
:
null
,
type
:
Reply
Type
.
Text
,
accountId
:
-
1
,
articles
:
[]
})
...
...
@@ -207,8 +81,7 @@ onMounted(async () => {
const
data
=
await
getUser
(
props
.
userId
)
user
.
nickname
=
data
.
nickname
?.
length
>
0
?
data
.
nickname
:
user
.
nickname
user
.
avatar
=
user
.
avatar
?.
length
>
0
?
data
.
avatar
:
user
.
avatar
user
.
accountId
=
data
.
accountId
queryParams
.
accountId
=
data
.
accountId
accountId
.
value
=
data
.
accountId
reply
.
value
.
accountId
=
data
.
accountId
refreshChange
()
...
...
@@ -220,7 +93,11 @@ const sendMsg = async () => {
return
}
// 公众号限制:客服消息,公众号只允许发送一条
if
(
reply
.
value
.
type
===
MsgType
.
News
&&
reply
.
value
.
articles
.
length
>
1
)
{
if
(
reply
.
value
.
type
===
ReplyType
.
News
&&
reply
.
value
.
articles
&&
reply
.
value
.
articles
.
length
>
1
)
{
reply
.
value
.
articles
=
[
reply
.
value
.
articles
[
0
]]
message
.
success
(
'图文消息条数限制在 1 条以内,已默认发送第一条'
)
}
...
...
@@ -229,18 +106,18 @@ const sendMsg = async () => {
sendLoading
.
value
=
false
list
.
value
=
[...
list
.
value
,
...[
data
]]
scrollToBottom
()
await
scrollToBottom
()
// 发送后清空数据
replySelectRef
.
value
?.
clear
()
}
const
load
ing
More
=
()
=>
{
const
loadMore
=
()
=>
{
queryParams
.
pageNo
++
getPage
(
queryParams
,
null
)
}
const
getPage
=
async
(
page
,
params
)
=>
{
const
getPage
=
async
(
page
:
any
,
params
:
any
)
=>
{
loading
.
value
=
true
let
dataTemp
=
await
getMessagePage
(
Object
.
assign
(
...
...
@@ -254,7 +131,7 @@ const getPage = async (page, params) => {
)
)
const
msgDiv
=
document
.
getElementById
(
'msg-div'
+
nowStr
.
value
)
const
msgDiv
=
document
.
getElementById
(
msgDivId
)
let
scrollHeight
=
0
if
(
msgDiv
)
{
scrollHeight
=
msgDiv
.
scrollHeight
...
...
@@ -264,24 +141,23 @@ const getPage = async (page, params) => {
list
.
value
=
[...
data
,
...
list
.
value
]
loading
.
value
=
false
if
(
data
.
length
<
queryParams
.
pageSize
||
data
.
length
===
0
)
{
load
More
.
value
=
false
has
More
.
value
=
false
}
queryParams
.
pageNo
=
page
.
pageNo
queryParams
.
pageSize
=
page
.
pageSize
// 滚动到原来的位置
if
(
queryParams
.
pageNo
===
1
)
{
// 定位到消息底部
scrollToBottom
()
await
scrollToBottom
()
}
else
if
(
data
.
length
!==
0
)
{
// 定位滚动条
await
nextTick
(()
=>
{
if
(
scrollHeight
!==
0
)
{
let
div
=
document
.
getElementById
(
'msg-div'
+
nowStr
.
value
)
if
(
div
&&
msgDiv
)
{
msgDiv
.
scrollTop
=
div
.
scrollHeight
-
scrollHeight
-
100
}
await
nextTick
()
if
(
scrollHeight
!==
0
)
{
let
div
=
document
.
getElementById
(
msgDivId
)
if
(
div
&&
msgDiv
)
{
msgDiv
.
scrollTop
=
div
.
scrollHeight
-
scrollHeight
-
100
}
}
)
}
}
}
...
...
@@ -290,26 +166,16 @@ const refreshChange = () => {
}
/** 定位到消息底部 */
const
scrollToBottom
=
()
=>
{
nextTick
(()
=>
{
let
div
=
document
.
getElementById
(
'msg-div'
+
nowStr
.
value
)
if
(
div
)
{
div
.
scrollTop
=
div
.
scrollHeight
}
})
const
scrollToBottom
=
async
()
=>
{
await
nextTick
()
let
div
=
document
.
getElementById
(
msgDivId
)
if
(
div
)
{
div
.
scrollTop
=
div
.
scrollHeight
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
/* 因为 joolun 实现依赖 avue 组件,该页面使用了 comment.scss、card.scc */
@import
'./comment.scss'
;
@import
'./card.scss'
;
.msg-main
{
margin-top
:
-30px
;
padding
:
10px
;
}
.msg-div
{
height
:
50vh
;
overflow
:
auto
;
...
...
@@ -322,11 +188,6 @@ const scrollToBottom = () => {
padding
:
10px
;
}
.avatar-div
{
text-align
:
center
;
width
:
80px
;
}
.send-but
{
float
:
right
;
margin-top
:
8px
;
...
...
src/views/mp/components/wx-msg/types.ts
View file @
f848f3ba
...
...
@@ -9,3 +9,9 @@ export enum MsgType {
Music
=
'music'
,
News
=
'news'
}
export
interface
User
{
nickname
:
string
avatar
:
string
accountId
:
number
}
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