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
d5f94077
authored
Aug 16, 2021
by
吴云建
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
会话优化
parent
4fd2e1d8
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
94 additions
and
75 deletions
components/chat-container.vue
components/chat-list-model.vue
components/chat-list.vue
components/chat-title.vue
components/message-list.vue
store/index.ts
store/model.ts
components/chat-container.vue
View file @
d5f94077
<
template
>
<div
class=
"chat-container"
:class=
"
{'is-in-page': isInPage}">
<div
class=
"search-wrap"
v-if=
"!modelName"
>
<el-input
class=
"keyword-input"
...
...
@@ -12,8 +13,8 @@
></el-input>
<i
v-if=
"!isInPage"
class=
"close-btn el-icon-close"
@
click=
"$emit('close')"
></i>
</div>
<chat-list
v-if=
"!modelName"
ref=
"chatListComp"
/>
<chat-list-model
v-if=
"modelName"
@
update-page-info=
"$emit('update-page-info', $event)"
ref=
"chatListModel"
/>
<chat-list
v-if=
"!modelName"
ref=
"chatListComp"
@
list-count-update=
"$emit('list-count-update', $event)"
/>
<chat-list-model
v-if=
"modelName"
@
list-count-update=
"$emit('list-count-update', $event)"
ref=
"chatListModel"
:modelName=
"modelName"
:listName=
"listName"
/>
<div
class=
"chat-content-wrap"
v-if=
"chatVisible && onShow"
>
<chat
:modelName=
"modelName"
/>
</div>
...
...
@@ -39,9 +40,10 @@ import buttonThrottle from "../utils/button-throttle";
export
default
class
ChatContainer
extends
Vue
{
@
Prop
(
Boolean
)
isInPage
:
boolean
;
@
Prop
(
String
)
modelName
:
string
;
@
Prop
(
String
)
listName
:
string
;
@
Prop
(
Boolean
)
isActive
:
boolean
;
private
onShow
=
false
;
private
orginPath
=
""
;
@
chatStore
.
State
(
ChatStore
.
STATE_CHAT_DIALOG_VISIBLE
)
private
readonly
chatVisible
!
:
ChatStore
.
STATE_CHAT_DIALOG_VISIBLE
;
...
...
@@ -58,23 +60,16 @@ export default class ChatContainer extends Vue {
this
.
chatListComp
.
search
(
this
.
searchKeyword
)
}
@
Watch
(
"
$route"
)
rout
eUpdate
()
{
if
(
this
.
$route
.
fullPath
!==
this
.
orginPath
)
{
this
.
onShow
=
false
;
@
Watch
(
"
isActive"
,
{
immediate
:
true
})
isActiv
eUpdate
()
{
this
.
onShow
=
this
.
isActive
;
if
(
!
this
.
onShow
)
{
this
.
chatListModel
&&
this
.
chatListModel
.
clearActiveId
();
}
else
{
this
.
onShow
=
true
}
}
private
onChatDrawerClose
(){
this
.
hideChat
()
}
created
()
{
this
.
orginPath
=
this
.
$route
.
fullPath
;
this
.
onShow
=
true
}
}
</
script
>
...
...
@@ -82,7 +77,7 @@ export default class ChatContainer extends Vue {
.chat-container
{
height
:
70vh
;
&.is-in-page
{
height
:
calc
(
100%
-
45px
)
;
height
:
100%
;
}
}
.keyword-input
{
...
...
@@ -104,7 +99,7 @@ export default class ChatContainer extends Vue {
}
.search-wrap
{
height
:
59px
;
border-bottom
:
1px
solid
#
ccc
;
border-bottom
:
1px
solid
#
ddd
;
}
.close-btn
{
float
:
right
;
...
...
components/chat-list-model.vue
View file @
d5f94077
...
...
@@ -3,7 +3,6 @@
<div
class=
"chat-list h-100"
>
<div
class=
"chat-list-scroll"
>
<el-scrollbar
ref=
"scrollbar"
class=
"list-scroll no-bottom-scrollbar"
>
<div
v-if=
"needUpdate"
class=
"need-update-tip"
@
click=
"refreshFirstPage"
>
数据有更新,请刷新
</div>
<div
v-for=
"item in chatRooms"
:key=
"'room_' + item.id"
...
...
@@ -108,16 +107,20 @@ export default class ModelChatList extends Vue {
@
Prop
({
type
:
Number
,
default
:
-
1
})
private
selected
!
:
number
;
@
Prop
({
type
:
String
})
private
modelName
!
:
string
;
@
Prop
({
type
:
String
})
private
listName
!
:
string
;
@
Ref
(
"scrollbar"
)
private
scrollbar
:
Vue
&
{
update
:
()
=>
void
};
private
modelName
=
""
;
private
listName
=
""
;
private
activeId
=
""
;
private
pageSize
=
10
;
private
total
=
0
;
private
currentPage
=
1
;
private
needUpdate
=
false
;
private
sseTs
=
0
;
private
get
chatRooms
()
{
...
...
@@ -129,10 +132,19 @@ export default class ModelChatList extends Vue {
}
private
async
getList
()
{
const
result
=
await
this
.
sdk
.
model
(
this
.
modelName
).
list
(
this
.
listName
||
undefined
).
query
({
let
result
=
await
this
.
sdk
.
model
(
this
.
modelName
).
list
(
this
.
listName
||
undefined
).
query
({
pageIndex
:
this
.
currentPage
,
item_size
:
this
.
pageSize
})
if
(
result
.
pageData
.
rows
.
length
===
0
&&
this
.
currentPage
!==
1
)
{
this
.
currentPage
=
1
;
if
(
result
.
pageData
.
record_count
>
0
)
{
result
=
await
this
.
sdk
.
model
(
this
.
modelName
).
list
(
this
.
listName
||
undefined
).
query
({
pageIndex
:
this
.
currentPage
,
item_size
:
this
.
pageSize
})
}
}
this
.
chatList
=
result
.
pageData
.
rows
.
map
(
it
=>
{
return
{
id
:
it
.
id
.
value
,
...
...
@@ -145,23 +157,14 @@ export default class ModelChatList extends Vue {
last_msg_content
:
it
.
LastMsgContent
.
value
,
last_msg_ts
:
it
.
LastMsgTime
.
value
,
last_msg_type
:
it
.
LastMsgType
.
value
,
title
:
it
.
t
itle
.
value
title
:
it
.
T
itle
.
value
}
as
ChatType
})
this
.
needUpdate
=
false
;
this
.
hideChat
();
this
.
total
=
result
.
pageData
.
record_count
;
this
.
$emit
(
"update-page-info"
,
{
title
:
result
.
pageData
.
title
})
}
private
async
refreshFirstPage
()
{
this
.
currentPage
=
1
;
await
this
.
getList
();
this
.
$emit
(
"list-count-update"
,
this
.
total
);
}
async
created
()
{
this
.
modelName
=
this
.
$route
.
params
.
modelName
;
this
.
listName
=
this
.
$route
.
params
.
listName
;
await
this
.
getList
();
this
.
setSource
(
ChatStore
.
StateChatSourceDirection
.
Server
);
this
.
scrollbar
.
update
();
...
...
@@ -171,10 +174,20 @@ export default class ModelChatList extends Vue {
}
onTransportMessage
(
e
:
any
)
{
let
index
=
e
.
dataUpdates
.
findIndex
(
it
=>
it
.
action
===
"startChat"
||
it
.
action
===
"csExitChat"
);
let
index
=
e
.
dataUpdates
.
findIndex
(
it
=>
it
.
action
===
"startChat"
||
it
.
action
===
"csExitChat"
||
it
.
action
===
"finishChat"
);
if
(
index
>
-
1
)
{
this
.
needUpdate
=
true
;
this
.
refreshListDebounce
();
}
}
private
refreshListDebounce
()
{
if
(
this
.
sseTs
)
{
return
}
setTimeout
(()
=>
{
this
.
sseTs
=
0
;
this
.
getList
();
},
1000
)
}
mounted
()
{
...
...
@@ -224,7 +237,7 @@ export default class ModelChatList extends Vue {
width
:
25%
;
box-sizing
:
border-box
;
height
:
100%
;
border-right
:
1px
solid
#
ccc
;
border-right
:
1px
solid
#
ddd
;
.title
{
padding-left
:
20px
;
line-height
:
59px
;
...
...
components/chat-list.vue
View file @
d5f94077
...
...
@@ -57,6 +57,7 @@ import avatar from "@/customer-service/components/avatar.vue";
import
{
chatStore
,
ChatStore
}
from
"@/customer-service/store/model"
;
import
{
formatTime
,
TimeFormatRule
}
from
"@/customer-service/utils/time"
;
import
{
Chat
as
ChatType
}
from
"@/customer-service/xim/models/chat"
;
import
{
EVENTS
}
from
"@/EventConsts"
export
function
parserMessage
(
type
:
string
,
rawMsg
:
string
)
{
if
(
!
type
)
return
""
;
...
...
@@ -110,10 +111,14 @@ export default class ChatList extends Vue {
@
Ref
(
"scrollbar"
)
private
scrollbar
:
Vue
&
{
update
:
()
=>
void
};
private
sseTs
=
0
;
private
unReadMsgCount
=
0
;
private
get
chatRooms
()
{
return
this
.
chatList
?.
list
.
filter
(
chat
=>
chat
.
title
.
indexOf
(
this
.
searchKeyword
)
>
-
1
)
||
[];
const
list
=
this
.
chatList
?.
list
.
filter
(
chat
=>
chat
.
title
.
indexOf
(
this
.
searchKeyword
)
>
-
1
)
||
[];
this
.
unReadMsgCount
=
list
.
filter
(
chat
=>
chat
.
unread_msg_count
>
0
).
length
;
this
.
$emit
(
"list-count-update"
,
this
.
unReadMsgCount
);
this
.
$eventHub
.
$emit
(
EVENTS
.
NewMsg
,
this
.
unReadMsgCount
);
return
list
;
}
private
isSelected
(
item
:
ChatType
)
{
...
...
@@ -126,39 +131,11 @@ export default class ChatList extends Vue {
async
created
()
{
await
this
.
getMyChatList
();
this
.
setSource
(
ChatStore
.
StateChatSourceDirection
.
Server
);
await
this
.
selectFirstChat
();
this
.
scrollbar
.
update
();
this
.
$onBeforeDestroy
(
await
this
.
sdk
.
model
(
"UniplatChat"
).
registerOnChange
(
this
.
onTransportMessage
)
)
}
mounted
()
{
this
.
saveMyId
();
this
.
goToOnlyRoom
();
}
onTransportMessage
()
{
const
ts
=
new
Date
().
getTime
();
if
(
ts
-
this
.
sseTs
>
100
)
{
this
.
getMyChatList
()
// this.hideChat()
this
.
sseTs
=
ts
;
}
}
private
goToOnlyRoom
()
{
if
(
this
.
chatRooms
.
length
===
1
)
{
const
wantedChat
=
this
.
chatRooms
[
0
];
this
.
goToChatRoom
(
wantedChat
);
}
}
private
async
selectFirstChat
()
{
if
(
this
.
chatId
!=
null
)
return
;
if
(
!
this
.
chatRooms
.
length
)
return
;
const
{
chat_id
}
=
this
.
chatRooms
[
0
];
this
.
saveChatId
(
chat_id
);
}
public
async
search
(
searchKeyword
:
string
)
{
...
...
@@ -174,6 +151,10 @@ export default class ChatList extends Vue {
this
.
showChat
();
this
.
close
();
if
(
data
.
unread_msg_count
>
0
)
{
data
.
unread_msg_count
=
0
;
}
}
private
raiseChatIdChanged
()
{
...
...
@@ -208,7 +189,7 @@ export default class ChatList extends Vue {
width
:
25%
;
box-sizing
:
border-box
;
height
:
calc
(
100%
-
59px
);
border-right
:
1px
solid
#
ccc
;
border-right
:
1px
solid
#
ddd
;
.title
{
padding-left
:
20px
;
line-height
:
59px
;
...
...
components/chat-title.vue
View file @
d5f94077
...
...
@@ -17,7 +17,7 @@
<div
class=
"title-buttons"
>
<el-button
class=
"button"
@
click=
"startReception"
round
v-if=
"!isChatMember"
>
开始
接待
</el-button
>
我要
接待
</el-button
>
<el-button
class=
"button"
@
click=
"exitChat"
round
v-if=
"isChatMember"
>
退出会话
</el-button
...
...
@@ -81,6 +81,9 @@ export default class ChatTitle extends Vue {
@
chatStore
.
State
(
ChatStore
.
STATE_CHAT_CURRENT_USER_TYPE
)
private
readonly
operatorType
!
:
ChatStore
.
STATE_CHAT_CURRENT_USER_TYPE
;
@
chatStore
.
Mutation
(
ChatStore
.
MUTATION_HIDE_CHAT
)
private
readonly
hideChat
:
ChatStore
.
MUTATION_HIDE_CHAT
;
private
get
chatMembersId
()
{
return
this
.
chatMembers
.
map
((
k
)
=>
+
k
.
eid
);
}
...
...
@@ -120,6 +123,7 @@ export default class ChatTitle extends Vue {
}
else
if
(
+
this
.
operatorType
>
25
){
await
this
.
_csExitChat
();
}
this
.
hideChat
();
}
catch
(
error
)
{
console
.
error
(
error
);
}
...
...
@@ -140,6 +144,7 @@ export default class ChatTitle extends Vue {
type
:
"warning"
,
})
await
this
.
_finishReception
();
this
.
hideChat
();
}
}
</
script
>
...
...
components/message-list.vue
View file @
d5f94077
...
...
@@ -193,11 +193,11 @@ export default class MessageList extends Vue {
if
(
wrap
)
{
if
(
delay
)
{
setTimeout
(()
=>
{
wrap
.
scrollTop
=
10000
;
wrap
.
scrollTop
=
10000
0
;
},
delay
);
return
;
}
wrap
.
scrollTop
=
10000
;
wrap
.
scrollTop
=
10000
0
;
}
});
}
...
...
store/index.ts
View file @
d5f94077
...
...
@@ -9,7 +9,7 @@ import { decode } from "../utils/jwt";
import
{
getUserInfo
}
from
"../utils/user-info"
;
import
Chat
from
"../xim"
;
import
chatType
from
"../xim/chat-type"
;
import
{
Chat
as
ChatType
}
from
"../xim/models/chat"
;
import
{
Chat
as
ChatType
,
Message
}
from
"../xim/models/chat"
;
import
xim
,
{
ChatNotifyListener
}
from
"../xim/xim"
;
import
{
ChatStatus
,
ChatStore
,
ChatStoreState
}
from
"./model"
;
...
...
@@ -85,6 +85,7 @@ export default {
[
ChatStore
.
STATE_CURRENT_CHAT_MEMBERS
]:
null
,
[
ChatStore
.
STATE_CURRENT_CHAT_TITLE
]:
""
,
[
ChatStore
.
STATE_FUNC_SCROLL_TO_BOTTOM
]:
()
=>
true
,
[
ChatStore
.
STATE_FUNC_ON_NEW_MSG
]:
()
=>
true
,
[
ChatStore
.
STATE_CURRENT_CHAT_INPUTING
]:
[],
[
ChatStore
.
STATE_CURRENT_CHAT_INITING
]:
false
,
[
ChatStore
.
STATE_CHAT_CURRENT_USER_TYPE
]:
null
,
...
...
@@ -214,6 +215,15 @@ export default {
[
ChatStore
.
MUTATION_CLEAR_FUNC_SCROLL_TO_BOTTOM
](
state
)
{
state
[
ChatStore
.
STATE_FUNC_SCROLL_TO_BOTTOM
]
=
()
=>
true
;
},
[
ChatStore
.
MUTATION_SAVE_FUNC_ON_NEW_MSG
](
state
,
data
:
ChatStore
.
STATE_FUNC_ON_NEW_MSG
)
{
state
[
ChatStore
.
STATE_FUNC_ON_NEW_MSG
]
=
data
;
},
[
ChatStore
.
MUTATION_CLEAR_FUNC_ON_NEW_MSG
](
state
)
{
state
[
ChatStore
.
STATE_FUNC_ON_NEW_MSG
]
=
()
=>
true
;
},
[
ChatStore
.
MUTATION_APPEND_SENDING_MESSAGE
]:
(
state
,
payload
:
ChatStore
.
STATE_CHAT_SENDING_MESSAGE
...
...
@@ -449,11 +459,18 @@ export default {
await
dispatch
(
ChatStore
.
ACTION_SAVE_CURRENT_CHAT_ID_VERSION
,
chatId
);
},
async
[
ChatStore
.
ACTION_REGISTER_EVENT
]({
dispatch
,
commit
,
state
})
{
const
chatId
=
state
[
ChatStore
.
STATE_CHAT_CURRENT_CHAT_ID
];
if
(
chatId
==
null
)
return
;
const
onNewMsg
=
()
=>
{
const
onNewMsg
=
(
e
:
Message
)
=>
{
if
(
e
.
chat_id
===
chatId
)
{
dispatch
(
ChatStore
.
ACTION_GET_FRESH_MESSAGE
);
}
state
[
ChatStore
.
STATE_FUNC_ON_NEW_MSG
](
e
);
};
const
chatId
=
state
[
ChatStore
.
STATE_CHAT_CURRENT_CHAT_ID
];
if
(
chatId
==
null
)
{
xim
.
off
(
"msg"
,
onNewMsg
);
xim
.
on
(
"msg"
,
onNewMsg
);
return
;
}
const
onMsgRead
:
ChatNotifyListener
=
async
(
e
)
=>
{
if
(
process
.
env
.
VUE_APP_API_CLIENT_ID
!==
...
...
@@ -491,11 +508,11 @@ export default {
commit
(
ChatStore
.
MUTATION_SAVE_CURRENT_CHAT_INPUTING
,
e
);
};
removeRegisterChatEvents
.
push
(()
=>
{
xim
.
off
(
"msg"
,
chatId
,
onNewMsg
);
xim
.
off
(
"msg"
,
onNewMsg
);
xim
.
off
(
"chat_notify"
,
"read"
,
onMsgRead
);
xim
.
off
(
"chat_notify"
,
"user.input"
,
onInputing
);
});
xim
.
on
(
"msg"
,
chatId
,
onNewMsg
);
xim
.
on
(
"msg"
,
onNewMsg
);
xim
.
on
(
"chat_notify"
,
"read"
,
onMsgRead
);
xim
.
on
(
"chat_notify"
,
"user.input"
,
onInputing
);
},
...
...
store/model.ts
View file @
d5f94077
...
...
@@ -82,6 +82,9 @@ export namespace ChatStore {
export
const
STATE_FUNC_SCROLL_TO_BOTTOM
=
"收到消息后滚动到底部的方法"
;
export
type
STATE_FUNC_SCROLL_TO_BOTTOM
=
()
=>
void
export
const
STATE_FUNC_ON_NEW_MSG
=
"收到消息回调方法"
;
export
type
STATE_FUNC_ON_NEW_MSG
=
(
e
:
chatDto
.
Message
)
=>
void
/* getter */
export
const
GETTER_CURRENT_CHAT_PRESENT_MEMBERS
=
"当前会话未退出的参与者"
;
export
type
GETTER_CURRENT_CHAT_PRESENT_MEMBERS
=
dto
.
ChatMembers
|
null
...
...
@@ -189,11 +192,15 @@ export namespace ChatStore {
export
const
MUTATION_SAVE_FUNC_SCROLL_TO_BOTTOM
=
"保存收到新消息后滚动到底部的方法"
;
export
type
MUTATION_SAVE_FUNC_SCROLL_TO_BOTTOM
=
(
func
:
()
=>
void
)
=>
void
export
const
MUTATION_CLEAR_FUNC_SCROLL_TO_BOTTOM
=
"删除收到新消息后滚动到底部的方法"
;
export
type
MUTATION_CLEAR_FUNC_SCROLL_TO_BOTTOM
=
()
=>
void
export
const
MUTATION_SAVE_FUNC_ON_NEW_MSG
=
"保存收到新消息后的方法"
;
export
type
MUTATION_SAVE_FUNC_ON_NEW_MSG
=
(
func
:
(
e
:
dto
.
Message
)
=>
void
)
=>
void
export
const
MUTATION_CLEAR_FUNC_ON_NEW_MSG
=
"删除收到新消息后的方法"
;
export
type
MUTATION_CLEAR_FUNC_ON_NEW_MSG
=
()
=>
void
export
const
MUTATION_APPEND_SENDING_MESSAGE
=
"appendSendingMessage"
;
export
type
MUTATION_APPEND_SENDING_MESSAGE
=
(
payload
:
dto
.
Message
)
=>
void
...
...
@@ -320,6 +327,7 @@ export interface ChatStoreState {
[
ChatStore
.
STATE_CURRENT_CHAT_MEMBERS
]:
ChatStore
.
STATE_CURRENT_CHAT_MEMBERS
;
[
ChatStore
.
STATE_CURRENT_CHAT_TITLE
]:
ChatStore
.
STATE_CURRENT_CHAT_TITLE
;
[
ChatStore
.
STATE_FUNC_SCROLL_TO_BOTTOM
]:
ChatStore
.
STATE_FUNC_SCROLL_TO_BOTTOM
;
[
ChatStore
.
STATE_FUNC_ON_NEW_MSG
]:
ChatStore
.
STATE_FUNC_ON_NEW_MSG
;
[
ChatStore
.
STATE_CURRENT_CHAT_INPUTING
]:
ChatStore
.
STATE_CURRENT_CHAT_INPUTING
;
[
ChatStore
.
STATE_CURRENT_CHAT_INITING
]:
ChatStore
.
STATE_CURRENT_CHAT_INITING
;
[
ChatStore
.
STATE_MY_CHAT_ROOM_LIST
]:
ChatStore
.
STATE_MY_CHAT_ROOM_LIST
;
...
...
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