Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
foreign
/
customer-service
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
7c3fe629
authored
Oct 08, 2021
by
zhousil
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
不同类型消息样式分离
parent
55070bdd
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
557 additions
and
562 deletions
components/message-item/audio-message.vue
components/message-item/file-message.vue
components/message-item/image-message.vue
components/message-item/text-message.vue
components/message-item/video-message.vue
components/message-item/withdraw-message.vue
components/message.vue
components/message-item/audio-message.vue
View file @
7c3fe629
...
@@ -25,63 +25,87 @@
...
@@ -25,63 +25,87 @@
</
template
>
</
template
>
<
script
lang=
"ts"
>
<
script
lang=
"ts"
>
import
{
Component
,
Ref
}
from
"vue-property-decorator"
;
import
{
Component
,
Ref
}
from
"vue-property-decorator"
;
import
BaseMessage
from
"./index"
;
import
BaseMessage
from
"./index"
;
import
VoiceIcon
from
"./voice.vue"
;
import
VoiceIcon
from
"./voice.vue"
;
@
Component
({
components
:
{
VoiceIcon
}
})
@
Component
({
components
:
{
VoiceIcon
}
})
export
default
class
Index
extends
BaseMessage
{
export
default
class
Index
extends
BaseMessage
{
@
Ref
(
"audio"
)
@
Ref
(
"audio"
)
private
readonly
audioRef
!
:
HTMLAudioElement
;
private
readonly
audioRef
!
:
HTMLAudioElement
;
private
playing
=
false
;
private
playing
=
false
;
private
get
duration
()
{
private
get
duration
()
{
const
v
=
this
.
messageBody
.
msg
.
duration
as
number
;
const
v
=
this
.
messageBody
.
msg
.
duration
as
number
;
return
v
||
0
;
return
v
||
0
;
}
}
private
get
durationInSecond
()
{
private
get
durationInSecond
()
{
return
Math
.
round
(
this
.
duration
/
1000
);
return
Math
.
round
(
this
.
duration
/
1000
);
}
}
private
get
getVoiceMessageWidth
()
{
private
get
getVoiceMessageWidth
()
{
if
(
this
.
fileFailed2Load
)
{
if
(
this
.
fileFailed2Load
)
{
return
35
;
return
35
;
}
const
d
=
this
.
duration
/
1000
;
if
(
d
<=
3
)
{
return
60
;
}
if
(
d
>=
60
)
{
return
200
;
}
return
60
+
d
;
}
}
const
d
=
this
.
duration
/
1000
;
if
(
d
<=
3
)
{
private
play
()
{
return
60
;
if
(
this
.
audioRef
?.
paused
)
{
this
.
audioRef
?.
load
();
this
.
audioRef
?.
play
();
}
else
{
this
.
audioRef
?.
pause
();
}
}
}
if
(
d
>=
60
)
{
private
onPlay
(
)
{
return
200
;
this
.
playing
=
true
;
}
}
return
60
+
d
;
private
onPause
()
{
}
this
.
playing
=
false
;
}
private
play
()
{
mounted
()
{
if
(
this
.
audioRef
?.
paused
)
{
this
.
buildMessageUrl
();
this
.
audioRef
?.
load
();
this
.
audioRef
?.
play
();
}
else
{
this
.
audioRef
?.
pause
();
}
}
}
}
</
script
>
private
onPlay
()
{
<
style
lang=
"less"
scoped
>
this
.
playing
=
true
;
.voice-message
{
}
height
:
40px
;
width
:
200px
;
private
onPause
()
{
&.can-play
{
this
.
playing
=
false
;
cursor
:
pointer
;
}
}
mounted
()
{
i
{
this
.
buildMessageUrl
();
font-size
:
16px
;
}
}
}
}
.my-message
{
</
script
>
.voice-message
{
>
div
{
flex-flow
:
row-reverse
;
}
<
style
lang=
"less"
scoped
></
style
>
svg
{
transform
:
rotateY
(
180deg
);
}
}
}
</
style
>
components/message-item/file-message.vue
View file @
7c3fe629
...
@@ -30,60 +30,69 @@
...
@@ -30,60 +30,69 @@
</
template
>
</
template
>
<
script
lang=
"ts"
>
<
script
lang=
"ts"
>
import
{
Component
}
from
"vue-property-decorator"
;
import
{
Component
}
from
"vue-property-decorator"
;
import
BaseMessage
from
"./index"
;
import
BaseMessage
from
"./index"
;
import
FileIcon
from
"./file-icon.vue"
;
import
FileIcon
from
"./file-icon.vue"
;
import
{
FileType
,
getFileType
}
from
"./file-controller"
;
import
{
FileType
,
getFileType
}
from
"./file-controller"
;
const
k
=
1024
,
const
k
=
1024
,
m
=
1024
*
k
,
m
=
1024
*
k
,
g
=
1024
*
m
,
g
=
1024
*
m
,
t
=
1024
*
g
;
t
=
1024
*
g
;
function
formatSize
(
size
:
number
)
{
function
formatSize
(
size
:
number
)
{
if
(
size
===
undefined
||
size
===
null
)
{
if
(
size
===
undefined
||
size
===
null
)
{
return
""
;
return
""
;
}
}
if
(
size
<
k
)
{
if
(
size
<
k
)
{
return
size
+
" B"
;
return
size
+
" B"
;
}
}
if
(
size
<
m
)
{
if
(
size
<
m
)
{
return
Number
((
size
/
k
).
toFixed
(
2
))
+
" KB"
;
return
Number
((
size
/
k
).
toFixed
(
2
))
+
" KB"
;
}
}
if
(
size
<
g
)
{
if
(
size
<
g
)
{
return
Number
((
size
/
m
).
toFixed
(
2
))
+
" MB"
;
return
Number
((
size
/
m
).
toFixed
(
2
))
+
" MB"
;
}
if
(
size
<
t
)
{
return
Number
((
size
/
g
).
toFixed
(
2
))
+
" GB"
;
}
return
Number
((
size
/
t
).
toFixed
(
2
))
+
" TB"
;
}
@
Component
({
components
:
{
FileIcon
}
})
export
default
class
Index
extends
BaseMessage
{
private
get
getAttachment
()
{
if
(
this
.
messageBody
)
{
return
this
.
messageBody
.
msg
.
name
;
}
}
return
"文件下载"
;
if
(
size
<
t
)
{
return
Number
((
size
/
g
).
toFixed
(
2
))
+
" GB"
;
}
return
Number
((
size
/
t
).
toFixed
(
2
))
+
" TB"
;
}
}
private
get
fileIcon
()
{
@
Component
({
components
:
{
FileIcon
}
})
if
(
this
.
value
)
{
export
default
class
Index
extends
BaseMessage
{
return
getFileType
(
this
.
messageBody
.
msg
.
name
);
private
get
getAttachment
()
{
if
(
this
.
messageBody
)
{
return
this
.
messageBody
.
msg
.
name
;
}
return
"文件下载"
;
}
}
return
FileType
.
Others
;
private
get
fileIcon
()
{
}
if
(
this
.
value
)
{
return
getFileType
(
this
.
messageBody
.
msg
.
name
);
}
private
format
(
v
:
number
)
{
return
FileType
.
Others
;
return
formatSize
(
v
);
}
}
mounted
()
{
private
format
(
v
:
number
)
{
this
.
buildMessageUrl
();
return
formatSize
(
v
);
}
mounted
()
{
this
.
buildMessageUrl
();
}
}
}
}
</
script
>
</
script
>
<
style
lang=
"less"
scoped
></
style
>
<
style
lang=
"less"
scoped
>
.file-message
{
background-color
:
transparent
!important
;
border-radius
:
4px
!important
;
border
:
1px
solid
#c5d4e5
;
.file-message-name
{
max-width
:
130px
;
}
}
</
style
>
components/message-item/image-message.vue
View file @
7c3fe629
...
@@ -16,24 +16,57 @@
...
@@ -16,24 +16,57 @@
</
template
>
</
template
>
<
script
lang=
"ts"
>
<
script
lang=
"ts"
>
import
{
Component
}
from
"vue-property-decorator"
;
import
{
Component
}
from
"vue-property-decorator"
;
import
{
FileType
}
from
"./file-controller"
;
import
{
FileType
}
from
"./file-controller"
;
import
BaseMessage
from
"./index"
;
import
BaseMessage
from
"./index"
;
import
FileIcon
from
"./file-icon.vue"
;
import
FileIcon
from
"./file-icon.vue"
;
@
Component
({
components
:
{
FileIcon
}
})
@
Component
({
components
:
{
FileIcon
}
})
export
default
class
Index
extends
BaseMessage
{
export
default
class
Index
extends
BaseMessage
{
private
readonly
image404
=
FileType
.
Image_404
;
private
readonly
image404
=
FileType
.
Image_404
;
private
onImageError
()
{
private
onImageError
()
{
this
.
fileFailed2Load
=
true
;
this
.
fileFailed2Load
=
true
;
this
.
messageRealUrl
=
""
;
this
.
messageRealUrl
=
""
;
}
}
mounted
()
{
mounted
()
{
this
.
buildMessageUrl
();
this
.
buildMessageUrl
();
}
}
}
}
</
script
>
</
script
>
<
style
lang=
"less"
scoped
></
style
>
<
style
lang=
"less"
scoped
>
.image-message
{
background-color
:
transparent
!important
;
border-radius
:
4px
!important
;
border
:
1px
solid
#c5d4e5
;
line-height
:
1
;
max-width
:
300px
;
box-sizing
:
content-box
;
img
{
width
:
100%
;
}
&
.image-404
{
background
:
#f7f8fa
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
.file-icon
{
margin
:
0
;
}
}
/
deep
/
.file-icon
{
margin-left
:
0
;
}
}
.my-message
{
&.
image-message
:
not
(.
image-404
)
{
background-color
:
transparent
!important
;
border-radius
:
4px
!important
;
border
:
1px
solid
#c5d4e5
;
}
}
</
style
>
components/message-item/text-message.vue
View file @
7c3fe629
...
@@ -6,31 +6,34 @@
...
@@ -6,31 +6,34 @@
</
template
>
</
template
>
<
script
lang=
"ts"
>
<
script
lang=
"ts"
>
import
{
replaceText2Link
}
from
"@/customer-service/utils"
;
import
{
replaceText2Link
}
from
"@/customer-service/utils"
;
import
xim
from
"@/customer-service/xim"
;
import
xim
from
"@/customer-service/xim"
;
import
{
Component
}
from
"vue-property-decorator"
;
import
{
Component
}
from
"vue-property-decorator"
;
import
BaseMessage
from
"./index"
;
import
BaseMessage
from
"./index"
;
@
Component
({
components
:
{}
})
@
Component
({
components
:
{}
})
export
default
class
Index
extends
BaseMessage
{
export
default
class
Index
extends
BaseMessage
{
private
readonly
emptyText
=
" "
;
private
readonly
emptyText
=
" "
;
private
format2Link
(
text
:
string
)
{
private
format2Link
(
text
:
string
)
{
let
t
=
replaceText2Link
(
text
);
let
t
=
replaceText2Link
(
text
);
const
keywords
=
xim
.
getMatchedTextKeywords
();
const
keywords
=
xim
.
getMatchedTextKeywords
();
for
(
const
item
of
keywords
)
{
for
(
const
item
of
keywords
)
{
const
r
=
new
RegExp
(
item
,
"g"
);
const
r
=
new
RegExp
(
item
,
"g"
);
t
=
t
.
replace
(
r
,
`<span class="highlight">
${
item
}
</span>`
);
t
=
t
.
replace
(
r
,
`<span class="highlight">
${
item
}
</span>`
);
}
return
t
;
}
}
return
t
;
}
}
}
</
script
>
</
script
>
<
style
lang=
"less"
scoped
>
<
style
lang=
"less"
scoped
>
.inline-text
{
.inline-text
{
/deep/
.highlight
{
display
:
inline-block
;
color
:
#e87005
;
white-space
:
pre-wrap
;
text-align
:
left
;
/deep/
.highlight
{
color
:
#e87005
;
}
}
}
}
</
style
>
</
style
>
\ No newline at end of file
components/message-item/video-message.vue
View file @
7c3fe629
...
@@ -25,4 +25,15 @@ export default class Index extends BaseMessage {
...
@@ -25,4 +25,15 @@ export default class Index extends BaseMessage {
}
}
</
script
>
</
script
>
<
style
lang=
"less"
scoped
></
style
>
<
style
lang=
"less"
scoped
>
.video-message
{
height
:
160px
;
width
:
200px
;
background-color
:
#000
!important
;
border-radius
:
0
!important
;
svg
{
cursor
:
pointer
;
}
}
</
style
>
components/message-item/withdraw-message.vue
View file @
7c3fe629
...
@@ -3,11 +3,20 @@
...
@@ -3,11 +3,20 @@
</
template
>
</
template
>
<
script
lang=
"ts"
>
<
script
lang=
"ts"
>
import
{
Component
}
from
"vue-property-decorator"
;
import
{
Component
}
from
"vue-property-decorator"
;
import
BaseMessage
from
"./index"
;
import
BaseMessage
from
"./index"
;
@
Component
({
components
:
{}
})
@
Component
({
components
:
{}
})
export
default
class
Index
extends
BaseMessage
{}
export
default
class
Index
extends
BaseMessage
{}
</
script
>
</
script
>
<
style
lang=
"less"
scoped
></
style
>
<
style
lang=
"less"
scoped
>
.my-message
{
.withdraw-message
{
background-color
:
transparent
!important
;
padding
:
0
4px
;
font-size
:
12px
;
color
:
#999
;
}
}
</
style
>
components/message.vue
View file @
7c3fe629
...
@@ -19,6 +19,9 @@
...
@@ -19,6 +19,9 @@
<component
<component
:is=
"messageComponent"
:is=
"messageComponent"
:user-name=
"userName"
:user-name=
"userName"
:class=
"
{
'my-message': isMyMessage,
}"
v-if="messageComponent"
v-if="messageComponent"
v-model="data"
v-model="data"
@open="openFile"
@open="openFile"
...
@@ -94,561 +97,463 @@
...
@@ -94,561 +97,463 @@
</template>
</template>
<
script
lang=
"ts"
>
<
script
lang=
"ts"
>
import
{
Component
,
Inject
,
Mixins
,
Prop
}
from
"vue-property-decorator"
;
import
{
Component
,
Inject
,
Mixins
,
Prop
}
from
"vue-property-decorator"
;
import
{
Filters
}
from
"../mixin/filter"
;
import
{
Filters
}
from
"../mixin/filter"
;
import
*
as
dto
from
"../model"
;
import
*
as
dto
from
"../model"
;
import
chat
from
"./../xim"
;
import
chat
from
"./../xim"
;
import
{
import
{
isAudio
,
isAudio
,
isImage
,
isImage
,
isVideo
,
isVideo
,
MAX_FILE_SIZE
,
MAX_FILE_SIZE
,
MAX_IMAGE_SIZE
,
MAX_IMAGE_SIZE
,
}
from
"./message-item/file-controller"
;
}
from
"./message-item/file-controller"
;
import
WhoReadList
from
"./who-read-list.vue"
;
import
WhoReadList
from
"./who-read-list.vue"
;
import
avatar
from
"@/customer-service/components/avatar.vue"
;
import
avatar
from
"@/customer-service/components/avatar.vue"
;
import
{
chatStore
,
ChatStore
}
from
"@/customer-service/store/model"
;
import
{
chatStore
,
ChatStore
}
from
"@/customer-service/store/model"
;
import
ximInstance
from
"../xim/xim"
;
import
ximInstance
from
"../xim/xim"
;
import
{
dbController
}
from
"../database"
;
import
{
dbController
}
from
"../database"
;
import
ImageMessage
from
"./message-item/image-message.vue"
;
import
ImageMessage
from
"./message-item/image-message.vue"
;
import
FileMessage
from
"./message-item/file-message.vue"
;
import
FileMessage
from
"./message-item/file-message.vue"
;
import
AudioMessage
from
"./message-item/audio-message.vue"
;
import
AudioMessage
from
"./message-item/audio-message.vue"
;
import
VideoMessage
from
"./message-item/video-message.vue"
;
import
VideoMessage
from
"./message-item/video-message.vue"
;
import
TextMessage
from
"./message-item/text-message.vue"
;
import
TextMessage
from
"./message-item/text-message.vue"
;
import
WithdrawMessage
from
"./message-item/withdraw-message.vue"
;
import
WithdrawMessage
from
"./message-item/withdraw-message.vue"
;
import
xim
from
"./../xim"
;
import
xim
from
"./../xim"
;
const
twoMinutes
=
2
*
60
*
1000
;
const
twoMinutes
=
2
*
60
*
1000
;
const
messageMapping
=
new
Map
<
dto
.
MessageType
,
string
>
([
const
messageMapping
=
new
Map
<
dto
.
MessageType
,
string
>
([
[
dto
.
MessageType
.
Image
,
"image-message"
],
[
dto
.
MessageType
.
Image
,
"image-message"
],
[
dto
.
MessageType
.
File
,
"file-message"
],
[
dto
.
MessageType
.
File
,
"file-message"
],
[
dto
.
MessageType
.
Video
,
"video-message"
],
[
dto
.
MessageType
.
Video
,
"video-message"
],
[
dto
.
MessageType
.
Voice
,
"audio-message"
],
[
dto
.
MessageType
.
Voice
,
"audio-message"
],
[
dto
.
MessageType
.
Text
,
"text-message"
],
[
dto
.
MessageType
.
Text
,
"text-message"
],
[
dto
.
MessageType
.
Withdraw
,
"withdraw-message"
],
[
dto
.
MessageType
.
Withdraw
,
"withdraw-message"
],
]);
]);
@
Component
({
@
Component
({
components
:
{
components
:
{
WhoReadList
,
WhoReadList
,
avatar
,
avatar
,
ImageMessage
,
ImageMessage
,
FileMessage
,
FileMessage
,
AudioMessage
,
AudioMessage
,
VideoMessage
,
VideoMessage
,
TextMessage
,
TextMessage
,
WithdrawMessage
,
WithdrawMessage
,
},
},
})
})
export
default
class
Message
extends
Mixins
(
Filters
)
{
export
default
class
Message
extends
Mixins
(
Filters
)
{
@
chatStore
.
State
(
ChatStore
.
STATE_CHAT_CURRENT_USER_UID
)
@
chatStore
.
State
(
ChatStore
.
STATE_CHAT_CURRENT_USER_UID
)
private
readonly
chatMyId
!
:
ChatStore
.
STATE_CHAT_CURRENT_USER_UID
;
private
readonly
chatMyId
!
:
ChatStore
.
STATE_CHAT_CURRENT_USER_UID
;
@
chatStore
.
Getter
(
ChatStore
.
GETTER_CURRENT_CHAT_PRESENT_MEMBERS
)
@
chatStore
.
Getter
(
ChatStore
.
GETTER_CURRENT_CHAT_PRESENT_MEMBERS
)
private
readonly
chatMembers
!
:
ChatStore
.
GETTER_CURRENT_CHAT_PRESENT_MEMBERS
;
private
readonly
chatMembers
!
:
ChatStore
.
GETTER_CURRENT_CHAT_PRESENT_MEMBERS
;
@
chatStore
.
State
(
ChatStore
.
STATE_CHAT_SOURCE
)
@
chatStore
.
State
(
ChatStore
.
STATE_CHAT_SOURCE
)
private
readonly
chatSource
!
:
ChatStore
.
STATE_CHAT_SOURCE
;
private
readonly
chatSource
!
:
ChatStore
.
STATE_CHAT_SOURCE
;
@
chatStore
.
State
(
ChatStore
.
STATE_CHAT_CURRENT_CHAT_ID
)
@
chatStore
.
State
(
ChatStore
.
STATE_CHAT_CURRENT_CHAT_ID
)
private
readonly
chatId
!
:
ChatStore
.
STATE_CHAT_CURRENT_CHAT_ID
;
private
readonly
chatId
!
:
ChatStore
.
STATE_CHAT_CURRENT_CHAT_ID
;
@
chatStore
.
Mutation
(
ChatStore
.
MUTATION_WITHDRAW
)
@
chatStore
.
Mutation
(
ChatStore
.
MUTATION_WITHDRAW
)
private
readonly
executeWithDraw
!
:
ChatStore
.
MUTATION_WITHDRAW
;
private
readonly
executeWithDraw
!
:
ChatStore
.
MUTATION_WITHDRAW
;
@
chatStore
.
Action
(
ChatStore
.
ACTION_SET_HANDLED
)
@
chatStore
.
Action
(
ChatStore
.
ACTION_SET_HANDLED
)
private
readonly
setHandled
!
:
ChatStore
.
ACTION_SET_HANDLED
;
private
readonly
setHandled
!
:
ChatStore
.
ACTION_SET_HANDLED
;
@
Prop
({
type
:
Object
,
default
:
()
=>
Object
.
create
(
null
)
})
@
Prop
({
type
:
Object
,
default
:
()
=>
Object
.
create
(
null
)
})
private
readonly
data
!
:
dto
.
Message
;
private
readonly
data
!
:
dto
.
Message
;
@
Prop
()
@
Prop
()
private
readonly
isSendingMessage
!
:
boolean
;
private
readonly
isSendingMessage
!
:
boolean
;
@
Prop
()
@
Prop
()
private
readonly
failed
!
:
boolean
;
private
readonly
failed
!
:
boolean
;
@
Prop
({
default
:
"circle"
})
@
Prop
({
default
:
"circle"
})
private
readonly
shape
!
:
string
;
private
readonly
shape
!
:
string
;
@
Inject
({
default
:
false
})
readonly
showReadSummary
!
:
boolean
;
@
Inject
({
default
:
false
})
readonly
showReadSummary
!
:
boolean
;
private
readonly
backend
=
chat
.
isBackend
();
private
readonly
backend
=
chat
.
isBackend
();
private
messageComponent
=
""
;
private
messageComponent
=
""
;
private
readListVisibility
=
false
;
private
readListVisibility
=
false
;
private
org
=
""
;
private
org
=
""
;
private
readerListOffset
=
false
;
private
readerListOffset
=
false
;
private
defaultMessageHandledStatus
=
dto
.
MessageHandled
.
Default
;
private
defaultMessageHandledStatus
=
dto
.
MessageHandled
.
Default
;
private
get
canWithdraw
()
{
private
get
canWithdraw
()
{
if
(
this
.
backend
&&
this
.
data
)
{
if
(
this
.
backend
&&
this
.
data
)
{
return
new
Date
().
valueOf
()
-
this
.
data
.
ts
*
1000
<
twoMinutes
;
return
new
Date
().
valueOf
()
-
this
.
data
.
ts
*
1000
<
twoMinutes
;
}
return
false
;
}
}
return
false
;
}
private
get
isWithdrawMessage
()
{
return
this
.
data
.
type
===
dto
.
MessageType
.
Withdraw
;
}
private
get
isAllRead
()
{
private
get
isWithdrawMessage
()
{
return
this
.
data
.
read_count
>=
this
.
data
.
total_read_count
;
return
this
.
data
.
type
===
dto
.
MessageType
.
Withdraw
;
}
}
private
get
messageBody
():
{
eid
?:
string
;
oid
?:
string
;
msg
:
any
}
{
private
get
isAllRead
()
{
if
(
this
.
data
)
{
return
this
.
data
.
read_count
>=
this
.
data
.
total_read_count
;
try
{
return
{
...
this
.
data
,
msg
:
JSON
.
parse
(
this
.
data
.
msg
)
};
}
catch
{
return
{
...
this
.
data
,
msg
:
JSON
.
parse
(
this
.
data
.
msg
.
replace
(
/
\n
/g
,
"\\n"
)),
};
}
}
}
return
{
msg
:
{
text
:
""
}
};
private
get
messageBody
():
{
eid
?:
string
;
oid
?:
string
;
msg
:
any
}
{
}
if
(
this
.
data
)
{
try
{
return
{
...
this
.
data
,
msg
:
JSON
.
parse
(
this
.
data
.
msg
)
};
}
catch
{
return
{
...
this
.
data
,
msg
:
JSON
.
parse
(
this
.
data
.
msg
.
replace
(
/
\n
/g
,
"\\n"
)),
};
}
}
private
get
handled
()
{
return
{
msg
:
{
text
:
""
}
};
if
(
this
.
data
)
{
return
this
.
defaultMessageHandledStatus
||
this
.
data
.
handled
;
}
}
return
dto
.
MessageHandled
.
Default
;
}
private
get
isMyMessage
()
{
private
get
handled
()
{
if
(
this
.
isSendingMessage
)
{
if
(
this
.
data
)
{
return
true
;
return
this
.
defaultMessageHandledStatus
||
this
.
data
.
handled
;
}
return
dto
.
MessageHandled
.
Default
;
}
}
const
senderEid
=
this
.
messageBody
.
eid
;
private
get
isMyMessage
()
{
return
senderEid
!
.
toString
()
===
this
.
chatMyId
!
.
toString
();
if
(
this
.
isSendingMessage
)
{
}
return
true
;
}
created
()
{
const
senderEid
=
this
.
messageBody
.
eid
;
this
.
messageComponent
=
messageMapping
.
get
(
this
.
messageType
)
as
string
;
return
senderEid
!
.
toString
()
===
this
.
chatMyId
!
.
toString
();
}
}
created
()
{
this
.
messageComponent
=
messageMapping
.
get
(
this
.
messageType
)
as
string
;
}
private
get
userName
()
{
private
get
userName
()
{
if
(
this
.
chatMembers
)
{
if
(
this
.
chatMembers
)
{
const
t
=
this
.
chatMembers
.
find
((
i
)
=>
i
.
eid
===
this
.
data
.
eid
);
const
t
=
this
.
chatMembers
.
find
((
i
)
=>
i
.
eid
===
this
.
data
.
eid
);
if
(
t
)
{
if
(
t
)
{
return
t
.
name
;
return
t
.
name
;
}
}
}
return
""
;
}
}
return
""
;
}
private
get
avatar
()
{
private
get
avatar
()
{
const
avatar
=
chat
.
getUserMapping
();
const
avatar
=
chat
.
getUserMapping
();
if
(
this
.
isSendingMessage
)
{
if
(
this
.
isSendingMessage
)
{
if
(
avatar
&&
this
.
chatMyId
)
{
if
(
avatar
&&
this
.
chatMyId
)
{
const
user
=
avatar
[
this
.
chatMyId
];
const
user
=
avatar
[
this
.
chatMyId
];
if
(
user
&&
user
.
avatar
)
{
if
(
user
&&
user
.
avatar
)
{
return
user
.
avatar
;
return
user
.
avatar
;
}
}
}
}
}
}
if
(
avatar
&&
this
.
data
)
{
if
(
avatar
&&
this
.
data
)
{
const
value
=
avatar
[
this
.
data
.
eid
];
const
value
=
avatar
[
this
.
data
.
eid
];
if
(
value
&&
value
.
avatar
)
{
if
(
value
&&
value
.
avatar
)
{
return
value
.
avatar
;
return
value
.
avatar
;
}
}
}
}
return
""
;
return
""
;
}
}
private
get
messageType
()
{
private
get
messageType
()
{
const
type
=
this
.
data
?.
type
;
const
type
=
this
.
data
?.
type
;
if
(
type
===
"file"
)
{
if
(
type
===
"file"
)
{
const
name
=
this
.
messageBody
?.
msg
.
name
;
const
name
=
this
.
messageBody
?.
msg
.
name
;
if
(
name
)
{
if
(
name
)
{
const
size
=
this
.
messageBody
?.
msg
.
size
;
const
size
=
this
.
messageBody
?.
msg
.
size
;
if
(
size
)
{
if
(
size
)
{
const
outImageSize
=
size
>
MAX_IMAGE_SIZE
;
const
outImageSize
=
size
>
MAX_IMAGE_SIZE
;
if
(
!
outImageSize
&&
isImage
(
name
))
{
if
(
!
outImageSize
&&
isImage
(
name
))
{
return
dto
.
MessageType
.
Image
;
return
dto
.
MessageType
.
Image
;
}
const
outSize
=
size
>
MAX_FILE_SIZE
;
if
(
!
outSize
)
{
if
(
isAudio
(
name
))
{
return
dto
.
MessageType
.
Voice
;
}
}
if
(
isVideo
(
name
))
{
const
outSize
=
size
>
MAX_FILE_SIZE
;
return
dto
.
MessageType
.
Video
;
if
(
!
outSize
)
{
if
(
isAudio
(
name
))
{
return
dto
.
MessageType
.
Voice
;
}
if
(
isVideo
(
name
))
{
return
dto
.
MessageType
.
Video
;
}
}
}
}
}
}
}
}
}
return
type
;
}
}
return
type
;
}
private
get
isTextMessage
()
{
private
get
isTextMessage
()
{
return
this
.
messageType
===
dto
.
MessageType
.
Text
;
return
this
.
messageType
===
dto
.
MessageType
.
Text
;
}
}
private
get
matchKeywords
()
{
private
get
matchKeywords
()
{
if
(
this
.
isTextMessage
&&
!
this
.
isMyMessage
)
{
if
(
this
.
isTextMessage
&&
!
this
.
isMyMessage
)
{
const
m
=
this
.
messageBody
.
msg
as
{
text
:
string
};
const
m
=
this
.
messageBody
.
msg
as
{
text
:
string
};
if
(
m
&&
m
.
text
)
{
if
(
m
&&
m
.
text
)
{
const
keywords
=
xim
.
getMatchedTextKeywords
();
const
keywords
=
xim
.
getMatchedTextKeywords
();
return
keywords
.
find
((
i
)
=>
m
.
text
.
includes
(
i
));
return
keywords
.
find
((
i
)
=>
m
.
text
.
includes
(
i
));
}
}
}
return
false
;
}
}
return
false
;
}
private
isCustomer
()
{
private
isCustomer
()
{
return
!
this
.
showReadSummary
;
return
!
this
.
showReadSummary
;
}
private
openFile
(
url
:
string
)
{
if
(
this
.
isSendingMessage
)
{
return
;
}
}
if
(
this
.
failed
)
{
return
;
private
openFile
(
url
:
string
)
{
if
(
this
.
isSendingMessage
)
{
return
;
}
if
(
this
.
failed
)
{
return
;
}
const
copy
=
{
...
this
.
messageBody
.
msg
};
copy
.
url
=
url
;
this
.
$emit
(
"open"
,
{
type
:
this
.
messageType
,
msg
:
copy
});
}
}
const
copy
=
{
...
this
.
messageBody
.
msg
};
copy
.
url
=
url
;
this
.
$emit
(
"open"
,
{
type
:
this
.
messageType
,
msg
:
copy
});
}
private
withdraw
()
{
private
withdraw
()
{
ximInstance
.
withdraw
(
this
.
chatId
!
,
this
.
data
.
id
).
finally
(()
=>
{
ximInstance
.
withdraw
(
this
.
chatId
!
,
this
.
data
.
id
).
finally
(()
=>
{
dbController
dbController
.
removeMessage
(
this
.
chatId
!
,
this
.
data
.
id
)
.
removeMessage
(
this
.
chatId
!
,
this
.
data
.
id
)
.
finally
(()
=>
{
.
finally
(()
=>
{
this
.
executeWithDraw
(
this
.
data
.
id
);
this
.
executeWithDraw
(
this
.
data
.
id
);
this
.
$emit
(
"withdraw"
,
this
.
data
.
id
);
this
.
$emit
(
"withdraw"
,
this
.
data
.
id
);
});
});
});
});
}
}
private
openReaderList
(
e
:
MouseEvent
)
{
private
openReaderList
(
e
:
MouseEvent
)
{
this
.
readerListOffset
=
e
.
x
<
450
;
this
.
readerListOffset
=
e
.
x
<
450
;
this
.
readListVisibility
=
true
;
this
.
readListVisibility
=
true
;
}
}
private
executeHandled
()
{
private
executeHandled
()
{
this
.
setHandled
({
this
.
setHandled
({
id
:
this
.
data
.
id
,
id
:
this
.
data
.
id
,
value
:
(
this
.
defaultMessageHandledStatus
=
value
:
(
this
.
defaultMessageHandledStatus
=
dto
.
MessageHandled
.
Handled
),
dto
.
MessageHandled
.
Handled
),
});
});
this
.
closeKeywordPopover
();
this
.
closeKeywordPopover
();
}
}
private
ignoredKeyword
()
{
private
ignoredKeyword
()
{
this
.
setHandled
({
this
.
setHandled
({
id
:
this
.
data
.
id
,
id
:
this
.
data
.
id
,
value
:
(
this
.
defaultMessageHandledStatus
=
value
:
(
this
.
defaultMessageHandledStatus
=
dto
.
MessageHandled
.
Ignored
),
dto
.
MessageHandled
.
Ignored
),
});
});
this
.
closeKeywordPopover
();
this
.
closeKeywordPopover
();
}
}
private
closeKeywordPopover
()
{
private
closeKeywordPopover
()
{
document
.
body
.
click
();
document
.
body
.
click
();
}
}
}
}
</
script
>
</
script
>
<
style
lang=
"less"
scoped
>
<
style
lang=
"less"
scoped
>
.message-con
{
.message-con
{
padding-bottom
:
20px
;
padding-bottom
:
20px
;
margin-right
:
15px
;
margin-right
:
15px
;
position
:
relative
;
position
:
relative
;
&.my-message
{
.msg-avatar
{
margin-right
:
0
;
margin-left
:
10px
;
}
.msg-detail
{
margin-top
:
0
;
background-color
:
#dbf2ff
;
border-radius
:
8px
0
8px
8px
;
&.
image-message
:
not
(.
image-404
),
&.my-message
{
&
.
file-message
{
.msg-avatar
{
background-color
:
transparent
;
margin-right
:
0
;
border-radius
:
4px
;
margin-left
:
10px
;
border
:
1px
solid
#c5d4e5
;
}
}
&
.voice-message
{
.msg-detail
{
>
div
{
margin-top
:
0
;
flex-flow
:
row-reverse
;
background-color
:
#dbf2ff
;
}
border-radius
:
8px
0
8px
8px
;
}
svg
{
.msg-read
{
transform
:
rotateY
(
180deg
);
display
:
inline-block
;
}
color
:
#bfe1ff
;
margin-right
:
15px
;
user-select
:
none
;
flex
:
none
;
margin-top
:
auto
;
}
}
&
.video-message
{
.download-icon
{
background-color
:
#000
;
margin-right
:
15px
;
border-radius
:
0
;
margin-left
:
0
;
margin-top
:
0
;
}
}
&
.withdraw-message
{
.withdraw
{
background-color
:
transparent
;
padding
:
0
4px
;
font-size
:
12px
;
color
:
#999
;
color
:
#999
;
position
:
absolute
;
bottom
:
0
;
right
:
0
;
font-size
:
12px
;
display
:
none
;
cursor
:
pointer
;
}
}
}
.msg-read
{
display
:
inline-block
;
color
:
#bfe1ff
;
margin-right
:
15px
;
user-select
:
none
;
flex
:
none
;
margin-top
:
auto
;
}
.download-icon
{
&
:hover
{
margin-right
:
15px
;
.withdraw
{
margin-left
:
0
;
display
:
inline-block
;
margin-top
:
0
;
}
}
}
}
.withdraw
{
&
.offset-bottom
{
color
:
#999
;
margin-bottom
:
30px
;
position
:
absolute
;
bottom
:
0
;
right
:
0
;
font-size
:
12px
;
display
:
none
;
cursor
:
pointer
;
}
}
&
:hover
{
>
i
{
.withdraw
{
height
:
16px
;
display
:
inline-block
;
font-size
:
16px
;
}
margin-right
:
10px
;
}
}
}
}
&
.offset-bottom
{
.msg-avatar
{
margin-bottom
:
30px
;
}
>
i
{
height
:
16px
;
font-size
:
16px
;
margin-right
:
10px
;
margin-right
:
10px
;
flex
:
40px
0
0
;
}
}
}
.msg-avatar
{
margin-right
:
10px
;
flex
:
40px
0
0
;
}
i
.msg-avatar
{
font-size
:
30px
;
background-color
:
#c0c4cc
;
border-radius
:
4px
;
width
:
40px
;
height
:
40px
;
&:before
{
i
.msg-avatar
{
position
:
relative
;
font-size
:
30px
;
left
:
5px
;
background-color
:
#c0c4cc
;
top
:
5px
;
color
:
#fff
;
}
}
.msg-name
{
font-size
:
14px
;
color
:
#888
;
text-align
:
right
;
margin-bottom
:
3px
;
min-height
:
16px
;
&.algin-left
{
text-align
:
left
;
}
}
.msg-content
{
text-align
:
right
;
&.algin-left
{
text-align
:
left
;
}
}
.msg-detail
{
margin-top
:
10px
;
font-size
:
14px
;
line-height
:
20px
;
background
:
#f5f6fa
;
border-radius
:
0px
8px
8px
;
padding
:
10px
;
word-break
:
break-word
;
&.image-message,
&.file-message
{
background-color
:
transparent
;
border-radius
:
4px
;
border-radius
:
4px
;
border
:
1px
solid
#c5d4e5
;
width
:
40px
;
}
height
:
40px
;
&
.image-message
{
line-height
:
1
;
&.image-404
{
background
:
#f7f8fa
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
.file-icon
{
&:before
{
margin
:
0
;
position
:
relative
;
}
left
:
5px
;
top
:
5px
;
color
:
#fff
;
}
}
}
/
deep
/
.file-icon
{
.msg-name
{
margin-left
:
0
;
font-size
:
14px
;
color
:
#888
;
text-align
:
right
;
margin-bottom
:
3px
;
min-height
:
16px
;
&.algin-left
{
text-align
:
left
;
}
}
}
}
&
.voice-message
{
.msg-content
{
height
:
40px
;
text-align
:
right
;
width
:
200px
;
&.algin-left
{
text-align
:
left
;
&.can-play
{
cursor
:
pointer
;
}
}
}
i
{
.msg-detail
{
font-size
:
16px
;
margin-top
:
10px
;
font-size
:
14px
;
line-height
:
20px
;
background
:
#f5f6fa
;
border-radius
:
0px
8px
8px
;
padding
:
10px
;
word-break
:
break-word
;
/deep/
img
{
max-width
:
300px
;
}
}
}
}
&
.video-message
{
.download-icon
{
height
:
160px
;
cursor
:
pointer
;
width
:
200px
;
text-decoration
:
none
;
background-color
:
#000
;
margin-left
:
15px
;
border-radius
:
0
;
margin-top
:
42px
;
svg
{
i
{
cursor
:
pointer
;
color
:
#fff
;
font-size
:
14px
;
}
}
}
}
&
.inline-text
{
.no-selection
{
display
:
inline-block
;
user-select
:
none
;
white-space
:
pre-wrap
;
text-align
:
left
;
}
}
.
file-message-name
{
.
pointer
{
max-width
:
130px
;
cursor
:
pointer
;
}
}
/
deep
/
img
{
.all
{
max-width
:
300px
;
color
:
#4389f8
;
}
}
}
.download-icon
{
.match-keyword
{
cursor
:
pointer
;
background-color
:
#fff3e0
;
text-decoration
:
none
;
border-radius
:
13px
;
margin-left
:
15px
;
padding
:
3px
8px
;
margin-top
:
42px
;
color
:
#e87005
;
position
:
absolute
;
i
{
bottom
:
-10px
;
color
:
#fff
;
left
:
0
;
font-size
:
14px
;
cursor
:
pointer
;
}
font-size
:
12px
;
}
.no-selection
{
user-select
:
none
;
}
.image-message
{
&.handled
{
max-width
:
300px
;
color
:
#59ba7b
;
box-sizing
:
content-box
;
background-color
:
#f0f0f0
;
img
{
cursor
:
default
;
width
:
100%
;
}
}
}
.pointer
{
cursor
:
pointer
;
}
.all
{
color
:
#4389f8
;
}
.match-keyword
{
background-color
:
#fff3e0
;
border-radius
:
13px
;
padding
:
3px
8px
;
color
:
#e87005
;
position
:
absolute
;
bottom
:
-10px
;
left
:
0
;
cursor
:
pointer
;
font-size
:
12px
;
&.handled
{
color
:
#59ba7b
;
background-color
:
#f0f0f0
;
cursor
:
default
;
}
&
.ignored
{
&
.ignored
{
color
:
#999
;
color
:
#999
;
background-color
:
#f0f0f0
;
background-color
:
#f0f0f0
;
cursor
:
default
;
cursor
:
default
;
}
}
i
{
i
{
margin-right
:
5px
;
margin-right
:
5px
;
}
}
}
}
.keyword-action
{
list-style
:
none
;
li
{
.keyword-action
{
list-style
:
none
;
list-style
:
none
;
padding
:
8px
10px
;
color
:
#077aec
;
cursor
:
pointer
;
&:hover
{
li
{
background-color
:
#f5f6fa
;
list-style
:
none
;
padding
:
8px
10px
;
color
:
#077aec
;
cursor
:
pointer
;
&:hover
{
background-color
:
#f5f6fa
;
}
}
}
}
}
}
</
style
>
</
style
>
<
style
lang=
"less"
>
<
style
lang=
"less"
>
.match-keyword-popover
{
.match-keyword-popover
{
padding
:
0
;
padding
:
0
;
}
}
</
style
>
</
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