Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
杨树贤
/
kefu_server
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
825ca73b
authored
Mar 21, 2020
by
chenxianqi
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
update code
parent
98c8f64f
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
301 additions
and
995 deletions
ui/kefu_client/plugins/help.js
ui/kefu_client/src/App.vue
ui/kefu_client/src/router.js
ui/kefu_client/src/store/actions.js
ui/kefu_client/src/store/getters.js
ui/kefu_client/src/store/mutations.js
ui/kefu_client/src/store/state.js
ui/kefu_client/src/views/kefu.vue
ui/kefu_client/src/views/workorder.vue
ui/kefu_client/plugins/help.js
View file @
825ca73b
var
moment
=
require
(
'moment'
);
import
axios
from
"axios"
;
import
*
as
qiniu
from
"qiniu-js"
;
// eslint-disable-next-line no-undef
var
Helps
=
{};
Helps
.
install
=
function
(
Vue
,
options
)
{
Vue
.
prototype
.
$myMethod
=
function
()
{
Vue
.
prototype
.
$myMethod
=
function
()
{
console
.
log
(
options
)
}
// 格式化日期
Vue
.
prototype
.
$formatUnixDate
=
function
(
unix
,
format
)
{
Vue
.
prototype
.
$formatUnixDate
=
function
(
unix
,
format
)
{
return
moment
(
parseInt
(
unix
+
'000'
)).
format
(
format
)
}
// 格式化日期(相对日期)
Vue
.
prototype
.
$formatFromNowDate
=
function
(
unix
,
format
=
"YYYY-MM-DD HH:mm"
)
{
if
(
moment
().
format
(
"YYYYMMDD"
)
==
moment
(
parseInt
(
unix
+
'000'
)).
format
(
"YYYYMMDD"
))
{
Vue
.
prototype
.
$formatFromNowDate
=
function
(
unix
,
format
=
"YYYY-MM-DD HH:mm"
)
{
if
(
moment
().
format
(
"YYYYMMDD"
)
==
moment
(
parseInt
(
unix
+
'000'
)).
format
(
"YYYYMMDD"
))
{
return
"今天 "
+
moment
(
parseInt
(
unix
+
'000'
)).
format
(
"HH:mm"
)
}
return
moment
(
parseInt
(
unix
+
'000'
)).
format
(
format
)
}
Vue
.
prototype
.
$robotNickname
=
function
(
id
)
{
Vue
.
prototype
.
$robotNickname
=
function
(
id
)
{
var
nickname
var
robots
=
this
.
$store
.
getters
.
robots
for
(
let
i
=
0
;
i
<
robots
.
length
;
i
++
)
{
if
(
robots
[
i
].
id
==
id
)
{
for
(
let
i
=
0
;
i
<
robots
.
length
;
i
++
)
{
if
(
robots
[
i
].
id
==
id
)
{
nickname
=
robots
[
i
].
nickname
}
}
return
nickname
}
// 判断是否是全面屏
Vue
.
prototype
.
$judgeBigScreen
=
function
(){
let
yes
=
false
;
const
rate
=
window
.
screen
.
height
/
window
.
screen
.
width
;
let
limit
=
window
.
screen
.
height
==
window
.
screen
.
availHeight
?
1.8
:
1.65
;
if
(
rate
>
limit
)
yes
=
true
;
return
yes
;
// 上传文件
Vue
.
prototype
.
$uploadFile
=
function
({
mode
,
file
,
percent
,
success
,
fail
})
{
var
qiniuObservable
=
null
;
const
fileName
=
parseInt
(
Math
.
random
()
*
10000
*
new
Date
().
getTime
())
+
file
.
name
.
substr
(
file
.
name
.
lastIndexOf
(
"."
));
// 系统内置
if
(
mode
==
1
)
{
let
fd
=
new
FormData
();
fd
.
append
(
"file"
,
file
);
fd
.
append
(
"file_name"
,
fileName
);
axios
.
post
(
"/public/upload"
,
fd
)
.
then
(
res
=>
{
if
(
success
)
success
(
res
.
data
.
data
);
})
.
catch
(()
=>
{
if
(
fail
)
fail
();
});
}
// 七牛云
else
if
(
mode
==
2
)
{
let
options
=
{
quality
:
0.92
,
noCompressIfLarger
:
true
,
maxWidth
:
1500
};
qiniu
.
compressImage
(
file
,
options
).
then
(
data
=>
{
const
observable
=
qiniu
.
upload
(
data
.
dist
,
fileName
,
self
.
uploadToken
.
secret
,
{},
{
mimeType
:
null
}
);
qiniuObservable
=
observable
.
subscribe
({
next
:
function
(
res
)
{
if
(
percent
)
percent
(
res
)
},
error
:
function
()
{
// 失败后再次使用FormData上传
var
formData
=
new
FormData
();
formData
.
append
(
"fileType"
,
"image"
);
formData
.
append
(
"fileName"
,
"file"
);
formData
.
append
(
"key"
,
fileName
);
formData
.
append
(
"token"
,
self
.
uploadToken
.
secret
);
formData
.
append
(
"file"
,
file
);
axios
.
post
(
"https://upload.qiniup.com"
,
formData
)
.
then
(()
=>
{
if
(
success
)
success
(
fileName
);
})
.
catch
(()
=>
{
if
(
fail
)
fail
();
});
},
complete
:
function
(
res
)
{
if
(
success
)
success
(
res
.
key
);
}
});
});
}
return
qiniuObservable
}
}
export
default
Helps
;
\ No newline at end of file
ui/kefu_client/src/App.vue
View file @
825ca73b
...
...
@@ -5,11 +5,6 @@
</
template
>
<
script
>
import
axios
from
"axios"
;
import
{
Toast
,
MessageBox
}
from
"mint-ui"
;
import
*
as
qiniu
from
"qiniu-js"
;
var
emojiService
=
require
(
"../resource/emoji"
);
import
BScroll
from
"better-scroll"
;
export
default
{
name
:
"app"
,
data
()
{
...
...
@@ -21,7 +16,6 @@ export default {
},
mounted
()
{
console
.
log
(
11111
)
this
.
handelUrl
()
},
methods
:
{
...
...
@@ -66,7 +60,7 @@ export default {
isArtificial
=
true
artificialAccount
=
parseInt
(
artificialAccountString
)
}
this
.
$store
.
commit
(
"updateState"
,
{
isShowHeader
,
isMobile
,
userAccount
,
uid
,
isArtificial
,
artificialAccount
,
robotAccount
})
this
.
$store
.
commit
(
"updateState"
,
{
isShowHeader
,
isMobile
,
userAccount
,
uid
,
isArtificial
,
artificialAccount
,
robotAccount
,
platform
})
},
// query 转json
queryToJson
(
str
)
{
...
...
@@ -120,732 +114,5 @@ body {
font-size
:
23px
!important
;
}
.mint-tabbar
{
z-index
:
999999999
!important
;
background-color
:
#fff
!important
;
}
.mint-loadmore-spinner
{
width
:
15px
!important
;
height
:
15px
!important
;
}
.mini-im-container
{
margin
:
0
auto
;
padding
:
50px
0
100px
;
overflow
:
hidden
;
height
:
100vh
;
box-sizing
:
border-box
;
-moz-box-sizing
:
border-box
;
-webkit-box-sizing
:
border-box
;
box-sizing
:
border-box
;
.input-ing
{
width
:
100vw
;
height
:
25px
;
position
:
fixed
;
top
:
0
;
left
:
0
;
right
:
0
;
background-color
:
#26a2ff
!important
;
z-index
:
9
;
color
:
#fff
;
margin
:
auto
;
text-align
:
center
;
font-size
:
14px
;
line-height
:
25px
;
}
.mini-im-loading
{
display
:
flex
;
min-width
:
240px
;
width
:
100%
;
position
:
fixed
;
top
:
0
;
left
:
0
;
right
:
0
;
background-color
:
#fff
!important
;
margin
:
auto
;
align-items
:
center
;
justify-content
:
center
;
}
}
.mini-im-container-no-pto
{
padding-top
:
0px
!important
;
}
.mini-im-tabbar-input
{
width
:
100%
;
padding
:
5px
10px
;
overflow
:
hidden
;
height
:
100px
;
display
:
flex
;
align-items
:
flex-end
;
justify-content
:
space-between
;
position
:
fixed
;
bottom
:
0
;
z-index
:
9
;
background-color
:
#fff
!important
;
border-top
:
1px
solid
#f2f2f2
;
left
:
0
;
right
:
0
;
margin
:
0
auto
;
-moz-box-sizing
:
border-box
;
-webkit-box-sizing
:
border-box
;
box-sizing
:
border-box
;
textarea
{
outline
:
none
;
-webkit-appearance
:
none
;
-webkit-tap-highlight-color
:
rgba
(
0
,
0
,
0
,
0
);
border
:
none
;
border-radius
:
5px
;
height
:
65px
;
flex-grow
:
1
;
padding
:
8px
0
;
font-size
:
14px
;
color
:
#666
;
background-color
:
#ffffff
;
display
:
block
;
box-sizing
:
border-box
;
resize
:
none
;
flex-shrink
:
1
;
flex-grow
:
1
;
width
:
100px
;
}
span
{
width
:
25px
;
height
:
25px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
img
{
width
:
28px
;
}
&
.expression-btn
{
position
:
absolute
;
left
:
45px
;
top
:
6px
;
z-index
:
99
;
}
&
.workorder-btn
{
position
:
absolute
;
left
:
70px
;
top
:
6px
;
z-index
:
99
;
width
70px
color
#999
font-size
14px
display
flex
img{
width
28px
hieght
28px
}
i
{
font-style
normal
}
}
&
.photo-btn
{
position
:
absolute
;
left
:
10px
;
top
:
5px
;
overflow
:
hidden
;
z-index
:
99
;
img
{
width
:
22px
;
}
input
{
width
:
100%
;
height
:
100%
;
position
:
absolute
;
top
:
0
;
left
:
0
;
opacity
:
0
;
}
}
&
.serverci
{
width
:
70px
;
position
:
absolute
;
flex-direction
:
row
;
justify-content
:
flex-end
;
top
:
5px
;
right
:
10px
;
img
{
width
:
26px
;
}
span
{
width
:
70px
;
background-color
:
#f3f3f370
;
color
:
#999
;
font-size
:
14px
;
}
&
.on
{
left
:
75px
;
justify-content
:
flex-start
;
right
:
initial
;
}
}
}
.mini-input-send
{
width
:
55px
;
height
:
30px
;
color
:
#fff
;
line-height
:
30px
;
text-align
:
center
;
border-radius
:
3px
;
border
:
none
;
font-size
:
14px
;
background
:
linear-gradient
(
to
right
,
#26a2ff
,
#736cde
);
flex-shrink
:
0
;
&:active
{
opacity
:
0.8
;
}
}
}
.mini-im-emoji
{
width
:
100%
;
height
:
100vh
;
position
:
fixed
;
top
:
0
;
left
:
0
;
right
:
0
;
padding
:
5px
0
;
z-index
:
9
;
margin
:
0
auto
;
background-color
:
#fff
;
.mini-im-emoji-content
{
width
:
100%
;
height
:
100vh
;
padding
:
50px
0
5px
;
position
:
absolute
;
box-sizing
:
border-box
;
-moz-box-sizing
:
border-box
;
-webkit-box-sizing
:
border-box
;
overflow
:
hidden
;
bottom
:
0
;
left
:
0
;
right
:
0
;
margin
:
0
auto
;
background-color
:
#fff
;
text-align
:
center
;
box-shadow
:
0px
2px
2px
1px
rgba
(
0
,
0
,
0
,
0.1
);
span
{
display
:
inline-block
;
width
:
28px
;
height
:
28px
;
padding
:
2px
;
text-align
:
center
;
font-size
:
23px
;
}
}
}
.mini-im-body
{
position
:
relative
;
height
:
100%
;
box-sizing
:
border-box
;
-moz-box-sizing
:
border-box
;
-webkit-box-sizing
:
border-box
;
background-color
:
#f3f3f3
;
margin
:
0
auto
;
overflow
:
hidden
;
z-index
:
1
;
ul
{
position
:
absolute
;
z-index
:
1
;
-webkit-tap-highlight-color
:
rgba
(
0
,
0
,
0
,
0
);
width
:
100%
;
-webkit-transform
:
translateZ
(
0
);
-moz-transform
:
translateZ
(
0
);
-ms-transform
:
translateZ
(
0
);
-o-transform
:
translateZ
(
0
);
transform
:
translateZ
(
0
);
-webkit-touch-callout
:
none
;
-webkit-user-select
:
none
;
-moz-user-select
:
none
;
-ms-user-select
:
none
;
user-select
:
none
;
-webkit-text-size-adjust
:
none
;
-moz-text-size-adjust
:
none
;
-ms-text-size-adjust
:
none
;
-o-text-size-adjust
:
none
;
text-size-adjust
:
none
;
}
.loading
{
height
:
100%
;
position
:
fixed
;
top
:
0
;
left
:
0
;
right
:
0
;
bottom
:
0
;
margin
:
auto
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
}
.top-loading
{
width
:
100%
;
height
:
35px
;
position
:
absolute
;
top
:
0
;
left
:
0
;
right
:
0
;
margin
:
0
auto
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
z-index
:
9
;
span
{
color
:
#999
;
font-size
:
13px
;
margin-left
:
5px
;
}
}
}
.mini-im-knowledge
{
width
:
100vw
;
height
:
100vh
;
background-color
:
rgba
(
0
,
0
,
0
,
0.2
);
position
:
fixed
;
z-index
:
8
;
top
:
0
;
left
:
0
;
right
:
0
;
margin
:
0
auto
;
box-sizing
:
border-box
;
padding-bottom
:
100px
;
display
:
flex
;
flex-direction
:
column
;
justify-content
:
flex-end
;
.mask
{
flex-grow
:
1
;
width
:
100vw
;
height
:
100px
;
}
span
{
background-color
:
#fff
;
font-size
:
14px
;
color
:
#666
;
padding
:
10px
;
}
ul
{
background-color
:
white
;
li
{
font-size
:
13px
;
cursor
:
pointer
;
color
:
#56b7ff
;
padding
:
6px
10px
;
border-top
:
1px
solid
#f2f2f2
;
}
}
}
.mint-loadmore
{
height
:
100%
;
}
.mint-loadmore-text
{
color
:
#666
;
font-size
:
14px
;
}
.mini-im-chat-list
{
padding
:
20px
10px
;
box-sizing
:
border-box
;
-moz-box-sizing
:
border-box
;
-webkit-box-sizing
:
border-box
;
.message-loading
{
padding-bottom
:
20px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
}
.mini-im-chat-item
{
display
:
flex
;
margin-bottom
:
15px
;
.chat-avatar
{
width
:
30px
;
height
:
30px
;
flex-grow
:
0
;
flex-shrink
:
0
;
overflow
:
hidden
;
margin-top
:
2px
;
box-shadow
:
1px
1px
2px
0px
rgba
(
0
,
0
,
0
,
0.3
);
border-radius
:
100%
;
img
{
width
:
100%
;
height
:
100%
;
border-radius
:
100%
;
}
}
.chat-content
{
width
:
100%
;
padding-left
:
10px
;
.chat-username
{
display
:
flex
;
align-items
:
center
;
padding-bottom
:
5px
;
span
{
font-size
:
12px
;
color
:
#666
;
font-weight
:
500
;
}
em
{
color
:
#666
;
font-size
:
12px
;
margin-left
:
8px
;
}
}
.chat-body
{
display
:
flex
;
align-items
:
flex-end
;
.cancel-btn
{
font-size
:
12px
;
color
:
#26a2ff
!important
;
margin-right
:
5px
;
}
.text
{
padding
:
5px
8px
;
background-color
:
#fff
;
border-radius
:
3px
;
font-size
:
14px
;
color
:
#333
;
max-width
:
85%
;
position
:
relative
;
box-shadow
:
1px
2px
2px
0px
rgba
(
0
,
0
,
0
,
0.1
);
-webkit-user-select
:
text
;
-moz-user-select
:
text
;
-o-user-select
:
text
;
user-select
:
text
;
word-break
:
break-all
;
&:before
{
content
:
''
;
display
:
block
;
position
:
absolute
;
top
:
5px
;
left
:
-9px
;
width
:
0
;
height
:
0
;
overflow
:
hidden
;
font-size
:
0
;
line-height
:
0
;
border
:
5px
;
border-radius
:
2px
;
border-style
:
dashed
solid
dashed
dashed
;
border-color
:
transparent
#fff
transparent
transparent
;
}
}
.photo
{
display
:
flex
;
align-items
:
flex-end
;
img
{
width
:
120px
;
display
:
block
;
border-radius
:
5px
;
cursor
:
pointer
;
}
span
{
font-size
:
12px
;
color
:
#999
;
padding-right
:
5px
;
}
}
.system
{
width
:
100%
;
display
:
flex
;
flex-direction
:
column
;
justify-content
:
center
;
span
{
text-align
:
center
;
font-size
:
12px
;
color
:
#999
;
}
.content
{
margin-top
:
1.5px
;
height
:
25px
;
text-align
:
center
;
span
{
padding
:
0
10px
;
text-align
:
center
;
font-size
:
12px
;
border-radius
:
5px
;
display
:
inline-block
;
line-height
:
22px
;
height
:
22px
;
min-width
:
80px
;
color
:
#949393
;
}
}
}
.knowledge
{
padding
:
5px
8px
;
background-color
:
#fff
;
border-radius
:
3px
;
font-size
:
13px
;
color
:
#333
;
max-width
:
80%
;
position
:
relative
;
box-shadow
:
1px
2px
2px
0px
rgba
(
0
,
0
,
0
,
0.1
);
display
:
flex
;
flex-direction
:
column
;
align-items
:
flex-start
;
.title
{
min-height
:
25px
;
font-size
:
14px
;
}
a
{
font-size
:
13px
;
color
:
#26a2ff
;
text-decoration
:
none
;
width
:
100%
;
display
:
flex
;
min-height
:
25px
;
}
}
}
}
&
.self
{
justify-content
:
flex-end
;
.chat-content
{
padding-right
:
10px
;
}
.chat-body
{
justify-content
:
flex-end
;
.text
{
box-shadow
:
-1px
1px
3px
0px
rgba
(
0
,
0
,
0
,
0.1
);
background-color
:
#26a2ff
;
color
:
#fff
;
-webkit-user-select
:
text
;
-moz-user-select
:
text
;
-o-user-select
:
text
;
user-select
:
text
;
word-break
:
break-all
;
&:before
{
left
:
inherit
;
right
:
-9px
;
border-style
:
dashed
dashed
dashed
solid
;
border-color
:
transparent
transparent
transparent
#26a2ff
;
}
}
}
.chat-avatar
{
order
:
1
;
}
.chat-username
{
justify-content
:
flex-end
;
em
{
order
:
-2
;
margin-right
:
5px
;
}
}
}
}
}
//
PC
端兼容样式
.mini-im-pc-container
{
width
:
360px
;
height
:
500px
;
position
:
fixed
;
top
:
0
;
left
:
0
;
right
:
0
;
bottom
:
0
;
margin
:
auto
;
display
:
flex
;
flex-direction
:
column
;
padding
:
0
!important
;
overflow
:
hidden
;
box-shadow
:
1px
1px
8px
2px
#ccc
;
.mini-im-loading,
.mini-im-emoji
{
width
:
360px
!important
;
height
:
500px
!important
;
bottom
:
0
;
margin
:
auto
!important
;
}
.mini-im-emoji
{
box-sizing
:
border-box
;
-moz-box-sizing
:
border-box
;
-webkit-box-sizing
:
border-box
;
}
.cancel-btn
{
cursor
:
pointer
;
}
.mini-im-emoji-content
{
padding
:
8px
!important
;
height
:
465px
!important
;
box-sizing
:
border-box
;
-moz-box-sizing
:
border-box
;
-webkit-box-sizing
:
border-box
;
span
{
width
:
26px
;
height
:
26px
;
cursor
:
pointer
;
}
}
.mini-im-body
{
width
:
360px
;
height
:
500px
;
position
:
static
!important
;
.mini-im-chat-list
{
padding
:
15px
!important
;
}
}
.mini-im-pc-header
{
z-index
:
999999999
!important
;
height
:
45px
;
background
:
linear-gradient
(
to
right
,
#26a2ff
,
#736cde
);
flex-shrink
:
0
;
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
padding
:
0
10px
;
color
:
#fff
;
.right
{
display
:
flex
;
align-items
:
center
;
cursor
:
pointer
;
img
{
width
:
20px
;
margin-right
:
5px
;
}
}
.title
{
font-size
:
14px
;
display
:
flex
;
align-items
:
center
;
img
{
width
:
20px
;
margin-right
:
5px
;
}
}
span
{
font-size
:
14px
;
}
.close-btn
{
width
:
20px
;
height
:
35px
;
text-align
:
right
;
line-height
:
35px
;
cursor
:
pointer
;
}
}
.mini-im-tabbar-input
{
height
:
130px
;
overflow
:
hidden
;
padding
:
5px
;
position
:
relative
;
box-sizing
:
border-box
;
-moz-box-sizing
:
border-box
;
-webkit-box-sizing
:
border-box
;
z-index
:
9
;
textarea
{
height
:
65px
;
padding-right
:
5px
;
margin
:
0
;
}
.mini-input-send
{
height
:
70px
;
width
:
60px
;
background
:
linear-gradient
(
to
right
,
#26a2ff
,
#736cde
);
color
:
#fff
;
border
:
0
;
cursor
:
pointer
;
border-radius
:
2px
;
}
span
.photo-btn
{
left
:
3px
;
}
span
.expression-btn
{
left
:
30px
;
}
}
}
.bscroll-vertical-scrollbar
{
right
:
0px
!important
;
height
:
100%
!important
;
.bscroll-indicator
{
width
:
4px
!important
;
border
:
0
!important
;
background
:
rgba
(
0
,
0
,
0
,
0.2
)
!important
;
right
:
0
!important
;
}
}
</
style
>
ui/kefu_client/src/router.js
View file @
825ca73b
...
...
@@ -7,7 +7,11 @@ const router = new Router({
routes
:
[
{
path
:
'/'
,
name
:
'kefu'
,
redirect
:
'/index'
},
{
path
:
'/index'
,
name
:
'index'
,
component
:
()
=>
import
(
'./views/kefu.vue'
)
},
{
...
...
ui/kefu_client/src/store/actions.js
View file @
825ca73b
const
axios
=
require
(
'axios'
)
import
axios
from
"axios"
;
export
default
{
ON_CHANGE_CAR_LIST
(
context
,
params
)
{
context
.
commit
(
'onChangeCarList'
,
params
)
// 获取消息列表
// params.timestamp
// params.callback
// params.oldMsg old msgs
onGetMessages
(
context
,
params
)
{
const
pageSize
=
20
;
axios
.
post
(
"/public/messages"
,
{
timestamp
:
params
.
timestamp
,
page_size
:
pageSize
})
.
then
(
response
=>
{
let
newMessage
=
[];
let
messages
=
response
.
data
.
data
.
list
||
[];
if
(
messages
.
length
<
pageSize
)
{
context
.
commit
(
'updateState'
,
{
isLoadMorEnd
:
true
})
}
if
(
params
.
oldMsg
.
length
==
0
&&
messages
.
length
>
0
)
{
newMessage
=
response
.
data
.
data
.
list
}
else
if
(
messages
.
length
>
0
)
{
newMessage
=
messages
.
concat
(
params
.
oldMsg
);
}
context
.
commit
(
'updateState'
,
{
messages
:
newMessage
})
if
(
params
.
callback
)
params
.
callback
()
})
.
catch
(
error
=>
{
console
.
log
(
error
);
});
},
// 获取用户位置
// APPKey 高德地图web应用key
onGetLocal
(
context
,
APPKey
)
{
axios
.
get
(
"https://restapi.amap.com/v3/ip?key="
+
APPKey
)
.
then
(
response
=>
{
if
(
response
.
data
.
province
)
{
context
.
commit
(
'updateState'
,
{
userLocal
:
response
.
data
.
province
+
response
.
data
.
city
})
}
})
.
catch
(
error
=>
{
console
.
error
(
error
);
});
},
// 清除未读消息
onCleanRead
()
{
axios
.
get
(
"/public/clean_read/"
);
},
// 上报最后活动时间
onUpdateLastActivity
()
{
axios
.
get
(
"/public/activity/"
);
},
// 用户是否在当前聊天页面
onToggleWindow
(
context
,
window
)
{
axios
.
put
(
"/public/window/"
,
{
window
});
},
// 用户是否在当前聊天页面
onGetCompanyInfo
(
context
)
{
axios
.
get
(
"/public/company"
)
.
then
(
response
=>
{
context
.
commit
(
'updateState'
,
{
companyInfo
:
response
.
data
.
data
})
})
.
catch
(
error
=>
{
console
.
error
(
error
);
});
},
// 获取上传配置
onGetUploadSecret
(
context
){
axios
.
get
(
"/public/secret"
).
then
(
response
=>
{
context
.
commit
(
'updateState'
,
{
uploadToken
:
response
.
data
.
data
})
});
}
}
\ No newline at end of file
ui/kefu_client/src/store/getters.js
View file @
825ca73b
...
...
@@ -25,5 +25,42 @@ export default {
},
robotAccount
(
state
)
{
return
state
.
robotAccount
},
isLoadMorEnd
(
state
)
{
return
state
.
isLoadMorEnd
},
messages
(
state
)
{
return
state
.
messages
||
[]
},
userLocal
(
state
)
{
return
state
.
userLocal
},
isLoadMorLoading
(
state
)
{
return
state
.
isLoadMorLoading
},
userInfo
(
state
)
{
return
state
.
userInfo
},
companyInfo
(
state
)
{
return
state
.
companyInfo
},
uploadToken
(
state
)
{
return
state
.
uploadToken
},
isIOS
()
{
return
!!
navigator
.
userAgent
.
match
(
/
\(
i
[^
;
]
+;
(
U;
)?
CPU.+Mac OS X/
);
},
isSafari
()
{
return
(
navigator
.
userAgent
.
indexOf
(
"Safari"
)
>
-
1
&&
navigator
.
userAgent
.
indexOf
(
"Chrome"
)
<
1
);
},
isJudgeBigScreen
()
{
let
yes
=
false
;
const
rate
=
window
.
screen
.
height
/
window
.
screen
.
width
;
let
limit
=
window
.
screen
.
height
==
window
.
screen
.
availHeight
?
1.8
:
1.65
;
if
(
rate
>
limit
)
yes
=
true
;
return
yes
;
}
}
\ No newline at end of file
ui/kefu_client/src/store/mutations.js
View file @
825ca73b
export
default
{
updateState
(
state
,
newObj
){
var
oldState
=
state
for
(
var
i
in
newObj
)
{
if
(
newObj
[
i
]
==
undefined
)
continue
s
tate
[
i
]
=
newObj
[
i
]
oldS
tate
[
i
]
=
newObj
[
i
]
}
state
=
oldState
}
}
\ No newline at end of file
ui/kefu_client/src/store/state.js
View file @
825ca73b
...
...
@@ -8,4 +8,12 @@ export default {
artificialAccount
:
null
,
// 客服账号ID
robotInfo
:
null
,
// 机器人信息
robotAccount
:
null
,
// 机器人账号ID
messages
:
[],
// 消息列表
isLoadMorEnd
:
false
,
// 是否已经到末尾
userLocal
:
""
,
// 用户地理位置
AmapAPPKey
:
""
,
// 高德地图web appkey
isLoadMorLoading
:
false
,
// 是否在加装更多消息loading
userInfo
:
{},
// 用户信息
companyInfo
:
null
,
// 公司信息
uploadToken
:
null
,
// 上传token
}
\ No newline at end of file
ui/kefu_client/src/views/kefu.vue
View file @
825ca73b
...
...
@@ -9,7 +9,7 @@
>
{{
inputPongIngString
}}
</span>
<mt-header
v-if=
"isShowHeader"
fixed
:title=
"isInputPongIng ? inputPongIngString : '在线客服'"
>
<div
slot=
"left"
>
<mt-button
@
click=
"
back
"
icon=
"back"
></mt-button>
<mt-button
@
click=
"
$router.go(-1)
"
icon=
"back"
></mt-button>
</div>
<mt-button
@
click=
"headRightBtn"
slot=
"right"
>
<img
title=
"人工客服"
v-if=
"!isArtificial"
src=
"http://qiniu.cmp520.com/kefu_icon_2000.png"
alt
/>
...
...
@@ -162,7 +162,6 @@
<span>
正在连接中~
</span>
</div>
</div>
<div
class=
"mini-im-loading"
v-if=
"isLoading"
>
<mt-spinner
type=
"triple-bounce"
color=
"#26a2ff"
></mt-spinner>
</div>
...
...
@@ -229,32 +228,23 @@
</template>
<
script
>
import
axios
from
"axios"
;
import
{
Toast
,
MessageBox
}
from
"mint-ui"
;
import
*
as
qiniu
from
"qiniu-js"
;
var
emojiService
=
require
(
"../../resource/emoji"
);
import
BScroll
from
"better-scroll"
;
import
{
mapGetters
}
from
'vuex'
import
{
mapGetters
}
from
"vuex"
;
export
default
{
name
:
"app"
,
data
()
{
return
{
messages
:
[],
isLoading
:
true
,
isShowTopLoading
:
true
,
userLocal
:
""
,
// 用户地理位置
isFirstGetMessage
:
true
,
// 第一次获取本地消息
chatValue
:
""
,
// 发送消息的内容
emojis
:
emojiService
.
emojiData
,
// emoji数据
showEmoji
:
false
,
// 是否显示emoji面板
userInfo
:
{},
// 用户信息
companyInfo
:
null
,
// 公司信息
uploadToken
:
null
,
// 上传token
isLoadMorEnd
:
false
,
isUserSendLongTimeSystemMessage
:
false
,
// 本次用户会话超时了是否发送了结束前提示语
isAdminSendLongTimeSystemMessage
:
false
,
// 本次客服会话超时了是否发送了结束前提示语
isInputPongIng
:
false
,
isLoadMorLoading
:
false
,
isSendPong
:
false
,
qiniuObservable
:
null
,
inputPongIngString
:
"对方正在输入..."
,
...
...
@@ -271,18 +261,6 @@ export default {
account
()
{
return
this
.
isArtificial
?
this
.
artificialAccount
:
this
.
robotAccount
;
},
isIOS
()
{
return
!!
navigator
.
userAgent
.
match
(
/
\(
i
[^
;
]
+;
(
U;
)?
CPU.+Mac OS X/
);
},
isSafari
()
{
return
(
navigator
.
userAgent
.
indexOf
(
"Safari"
)
>
-
1
&&
navigator
.
userAgent
.
indexOf
(
"Chrome"
)
<
1
);
},
isJudgeBigScreen
()
{
return
this
.
$judgeBigScreen
();
},
viewMessage
()
{
var
messages
=
this
.
messages
;
for
(
let
i
=
0
;
i
<
messages
.
length
;
i
++
)
{
...
...
@@ -295,21 +273,31 @@ export default {
}
return
messages
;
},
messages
()
{
return
this
.
$store
.
getters
.
messages
.
map
(
i
=>
this
.
handlerMessage
(
i
));
},
...
mapGetters
([
'platform'
,
'isArtificial'
,
'isShowHeader'
,
'isMobile'
,
'uid'
,
'userAccount'
,
'artificialAccount'
,
'robotInfo'
,
'robotAccount'
,
"platform"
,
"isArtificial"
,
"isShowHeader"
,
"isMobile"
,
"uid"
,
"userAccount"
,
"artificialAccount"
,
"robotInfo"
,
"robotAccount"
,
"isLoadMorEnd"
,
"userLocal"
,
"isLoadMorLoading"
,
"userInfo"
,
"isSafari"
,
"isIOS"
,
"isJudgeBigScreen"
])
},
mounted
()
{
setTimeout
(()
=>
{
this
.
isLoading
=
fals
e
;
this
.
isLoading
=
tru
e
;
this
.
scroll
=
new
BScroll
(
this
.
$refs
.
miniImBody
,
{
click
:
true
,
tab
:
true
,
...
...
@@ -337,12 +325,11 @@ export default {
document
.
addEventListener
(
"paste"
,
this
.
inputPaste
,
false
);
},
beforeDestroy
()
{
this
.
toggleWindow
(
0
);
this
.
$store
.
dispatch
(
"onToggleWindow"
,
0
);
},
methods
:
{
// runApp
runApp
()
{
const
IM
=
this
.
$mimcInstance
;
const
user
=
this
.
$mimcInstance
.
getLocalCacheUser
();
if
(
user
&&
...
...
@@ -352,7 +339,7 @@ export default {
)
{
localStorage
.
clear
();
}
IM
.
init
(
this
.
$mimcInstance
.
init
(
{
type
:
0
,
// 默认0
address
:
this
.
userLocal
,
...
...
@@ -365,31 +352,31 @@ export default {
if
(
!
user
)
{
setTimeout
(()
=>
this
.
runApp
(),
1000
);
}
else
{
this
.
isLoading
=
false
;
// handelEvent
this
.
handelEvent
();
// user
this
.
userInfo
=
user
;
this
.
$store
.
commit
(
"updateState"
,
{
userAccount
:
user
.
id
});
this
.
$store
.
commit
(
"updateState"
,
{
userAccount
:
user
.
id
,
userInfo
:
user
});
// robot
var
robot
=
IM
.
robot
console
.
log
(
robot
)
var
robot
=
this
.
$mimcInstance
.
robot
;
console
.
log
(
robot
)
;
localStorage
.
setItem
(
"robot_"
+
robot
.
id
,
JSON
.
stringify
(
robot
));
this
.
$store
.
commit
(
"updateState"
,
{
robotAccount
:
robot
.
id
,
robotInfo
:
robot
});
// 清除未读消息
this
.
cleanRead
(
user
.
id
);
this
.
$store
.
dispatch
(
"onCleanRead"
);
// 更换toggle
this
.
toggleWindow
(
1
);
this
.
$store
.
dispatch
(
"onToggleWindow"
,
1
);
// 登录完成发送一条握手消息给机器人
IM
.
login
(()
=>
{
this
.
$mimcInstance
.
login
(()
=>
{
setTimeout
(()
=>
{
// 获取消息记录
this
.
getMessageRecord
();
if
(
!
this
.
artificialAccount
)
{
console
.
log
(
"握手消息"
);
IM
.
sendMessage
(
"handshake"
,
this
.
robotAccount
,
""
);
this
.
$mimcInstance
.
sendMessage
(
"handshake"
,
this
.
robotAccount
,
""
);
}
this
.
scrollIntoBottom
();
},
500
);
...
...
@@ -403,8 +390,12 @@ export default {
},
// handelEvent
handelEvent
()
{
// 发起请求
this
.
getAllhttp
();
// 获取公司信息
this
.
$store
.
dispatch
(
"onGetCompanyInfo"
)
// 获取上传配置信息
this
.
$store
.
dispatch
(
"onGetUploadSecret"
)
// 上报活动时间
this
.
upLastActivity
();
...
...
@@ -445,25 +436,14 @@ export default {
// 计算用户是否长时间未回复弹出给出提示
this
.
onCheckIsloogTimeNotCallBack
();
// 关闭top loading
setTimeout
(()
=>
this
.
isShowTopLoading
=
false
,
1000
)
},
// 根据IP获取用户地理位置
getLocal
()
{
var
APPKey
=
""
;
// 高德地图web应用key
axios
.
get
(
"https://restapi.amap.com/v3/ip?key="
+
APPKey
)
.
then
(
response
=>
{
if
(
response
.
data
.
province
)
{
console
.
log
(
response
.
data
.
province
+
response
.
data
.
city
);
this
.
userLocal
=
response
.
data
.
province
+
response
.
data
.
city
;
}
})
.
catch
(
error
=>
{
console
.
error
(
error
);
});
},
// 刷新页面
resetLoad
()
{
window
.
location
.
reload
();
this
.
$store
.
dispatch
(
"onGetLocal"
,
this
.
$store
.
state
.
AmapAPPKey
);
},
// 快捷键换行
enterShift
(
event
)
{
...
...
@@ -499,18 +479,6 @@ export default {
);
}
},
// 清除未读消息
cleanRead
(
id
)
{
axios
.
get
(
"/public/clean_read/"
);
},
// 用户是否在当前聊天页面
toggleWindow
(
window
)
{
axios
.
put
(
"/public/window/"
,
{
window
:
window
});
},
// 返回上一页按钮
back
()
{
history
.
go
(
-
1
);
},
// 是否显示用户头像信息(系统消息隐藏)
isShowInfo
(
biz_type
)
{
return
(
...
...
@@ -535,7 +503,7 @@ export default {
upLastActivity
()
{
this
.
onCheckIsOutSession
();
const
user
=
this
.
$mimcInstance
.
getLocalCacheUser
();
if
(
user
)
axios
.
get
(
"/public/activity/
"
);
if
(
user
)
this
.
$store
.
dispatch
(
"onUpdateLastActivity
"
);
if
(
this
.
isArtificial
)
{
localStorage
.
setItem
(
"artificialTime"
,
Date
.
now
());
}
...
...
@@ -554,15 +522,15 @@ export default {
}
}
},
// 获取
本地
更多数据
// 获取更多数据
loadMorData
()
{
if
(
this
.
isLoadMorLoading
)
return
;
if
(
this
.
isLoadMorEnd
)
return
;
this
.
isLoadMorLoading
=
true
;
this
.
$store
.
commit
(
"updateState"
,
{
isLoadMorLoading
:
true
})
;
setTimeout
(()
=>
{
// 获取消息记录
this
.
getMessageRecord
();
this
.
isLoadMorLoading
=
false
;
this
.
$store
.
commit
(
"updateState"
,
{
isLoadMorLoading
:
false
})
;
},
1000
);
},
// 获取本地缓存的客服信息
...
...
@@ -606,8 +574,7 @@ export default {
Toast
({
message
:
"上传失败,请重新上传!"
});
const
IM
=
self
.
$mimcInstance
;
var
message
=
IM
.
createLocalMessage
(
var
message
=
this
.
$mimcInstance
.
createLocalMessage
(
"system"
,
self
.
account
,
"您刚刚上传的图片失败了,请重新上传!"
...
...
@@ -641,39 +608,12 @@ export default {
self
.
$previewRefresh
();
self
.
scrollIntoBottom
();
// 系统内置
if
(
self
.
uploadToken
.
mode
==
1
)
{
let
fd
=
new
FormData
();
fd
.
append
(
"file"
,
file
);
fd
.
append
(
"file_name"
,
fileName
);
axios
.
post
(
"/public/upload"
,
fd
)
.
then
(
res
=>
{
uploadSuccess
(
res
.
data
.
data
);
})
.
catch
(()
=>
{
uploadError
();
});
}
// 七牛云
else
if
(
self
.
uploadToken
.
mode
==
2
)
{
let
options
=
{
quality
:
0.92
,
noCompressIfLarger
:
true
,
maxWidth
:
1500
};
qiniu
.
compressImage
(
file
,
options
).
then
(
data
=>
{
const
observable
=
qiniu
.
upload
(
data
.
dist
,
fileName
,
self
.
uploadToken
.
secret
,
{},
{
mimeType
:
null
}
);
self
.
qiniuObservable
=
observable
.
subscribe
({
next
:
function
(
res
)
{
// 上传
self
.
qiniuObservable
=
self
.
$uploadFile
({
file
,
mode
:
self
.
uploadToken
.
mode
,
// 七牛才会执行
percent
(
res
){
localMessage
.
percent
=
Math
.
ceil
(
res
.
total
.
percent
);
if
(
res
.
total
.
size
<
1
)
{
self
.
qiniuObservable
.
unsubscribe
();
...
...
@@ -683,29 +623,15 @@ export default {
});
}
},
error
:
function
()
{
// 失败后再次使用FormData上传
var
formData
=
new
FormData
();
formData
.
append
(
"fileType"
,
"image"
);
formData
.
append
(
"fileName"
,
"file"
);
formData
.
append
(
"key"
,
fileName
);
formData
.
append
(
"token"
,
self
.
uploadToken
.
secret
);
formData
.
append
(
"file"
,
file
);
axios
.
post
(
"https://upload.qiniup.com"
,
formData
)
.
then
(()
=>
{
uploadSuccess
(
fileName
);
})
.
catch
(()
=>
{
uploadError
();
});
success
(
src
){
uploadSuccess
(
src
);
},
complete
:
function
(
res
)
{
uploadSuccess
(
res
.
key
);
fail
()
{
uploadError
(
);
}
});
});
}
};
},
// 滚动条置底
...
...
@@ -725,36 +651,6 @@ export default {
window
.
chatInputInterval
=
null
;
window
.
scroll
(
0
,
0
);
},
// 获取上传配置
getUploadSecret
()
{
return
axios
.
get
(
"/public/secret"
).
then
(
response
=>
{
this
.
uploadToken
=
response
.
data
.
data
;
});
},
// 获取公司信息
getCompanyInfo
()
{
return
axios
.
get
(
"/public/company"
)
.
then
(
response
=>
{
this
.
companyInfo
=
response
.
data
.
data
;
})
.
catch
(
error
=>
{
Toast
({
message
:
error
.
response
.
data
.
message
});
});
},
// 发起并发请求
getAllhttp
()
{
axios
.
all
([
this
.
getCompanyInfo
(),
this
.
getUploadSecret
()])
.
then
(
axios
.
spread
(()
=>
{
this
.
isShowTopLoading
=
false
;
})
)
.
catch
(()
=>
setTimeout
(()
=>
this
.
getAllhttp
(),
1000
));
},
// 接收消息
receiveP2PMsg
(
message
)
{
console
.
log
(
message
);
...
...
@@ -849,8 +745,7 @@ export default {
}
var
chatValue
=
this
.
chatValue
.
trim
();
if
(
chatValue
==
""
)
return
;
const
IM
=
this
.
$mimcInstance
;
const
message
=
IM
.
sendMessage
(
"text"
,
this
.
account
,
chatValue
);
const
message
=
this
.
$mimcInstance
.
sendMessage
(
"text"
,
this
.
account
,
chatValue
);
message
.
isShowCancel
=
true
;
setTimeout
(()
=>
(
message
.
isShowCancel
=
false
),
10000
);
this
.
messagesPushMemory
(
message
);
...
...
@@ -859,8 +754,7 @@ export default {
},
// 撤回消息
cancelMessage
(
key
)
{
const
IM
=
this
.
$mimcInstance
;
const
message
=
IM
.
sendMessage
(
"cancel"
,
this
.
account
,
key
);
const
message
=
this
.
$mimcInstance
.
sendMessage
(
"cancel"
,
this
.
account
,
key
);
this
.
messagesPushMemory
(
message
);
this
.
removeMessage
(
this
.
userInfo
.
id
,
key
);
if
(
this
.
qiniuObservable
)
this
.
qiniuObservable
.
unsubscribe
();
...
...
@@ -868,8 +762,7 @@ export default {
// 点击知识库消息
sendKnowledgeMessage
(
content
)
{
this
.
handshakeKeywordList
=
[];
const
IM
=
this
.
$mimcInstance
;
const
message
=
IM
.
sendMessage
(
"text"
,
this
.
account
,
content
);
const
message
=
this
.
$mimcInstance
.
sendMessage
(
"text"
,
this
.
account
,
content
);
this
.
messagesPushMemory
(
message
);
this
.
chatValue
=
""
;
},
...
...
@@ -927,32 +820,15 @@ export default {
},
// 获取服务器消息列表
getMessageRecord
()
{
const
pageSize
=
20
;
let
uid
=
this
.
userInfo
.
id
;
let
timestamp
=
this
.
messages
.
length
==
0
?
parseInt
((
new
Date
().
getTime
()
+
" "
).
substr
(
0
,
10
))
:
this
.
messages
[
0
].
timestamp
;
axios
.
post
(
"/public/messages"
,
{
timestamp
:
timestamp
,
page_size
:
pageSize
})
.
then
(
response
=>
{
let
messages
=
response
.
data
.
data
.
list
||
[];
if
(
messages
.
length
<
pageSize
)
this
.
isLoadMorEnd
=
true
;
if
(
this
.
messages
.
length
==
0
&&
messages
.
length
>
0
)
{
this
.
messages
=
response
.
data
.
data
.
list
.
map
(
i
=>
this
.
handlerMessage
(
i
)
);
this
.
scrollIntoBottom
();
}
else
if
(
messages
.
length
>
0
)
{
messages
=
messages
.
map
(
i
=>
this
.
handlerMessage
(
i
));
this
.
messages
=
messages
.
concat
(
this
.
messages
);
}
})
.
catch
(
error
=>
{
console
.
log
(
error
);
let
oldMsg
=
this
.
messages
;
this
.
$store
.
dispatch
(
"onGetMessages"
,
{
timestamp
,
oldMsg
,
callback
:
()
=>
this
.
scrollIntoBottom
()
});
},
// 敲键盘发送pong事件消息
...
...
@@ -974,7 +850,7 @@ export default {
continue
;
newMessages
.
push
(
this
.
messages
[
i
]);
}
this
.
messages
=
newMessages
;
this
.
$store
.
commit
(
"updateState"
,
{
messages
:
newMessages
})
;
},
// 生成query
createLinkQuery
()
{
...
...
@@ -987,7 +863,11 @@ export default {
let
uid
=
this
.
uid
?
"&uid="
+
this
.
uid
:
""
;
let
query
=
"?h="
+
h
+
"&m="
+
m
+
"&p="
+
p
+
"&r="
+
r
+
"&a="
+
a
+
u
+
uid
;
history
.
replaceState
(
null
,
null
,
query
);
history
.
replaceState
(
null
,
null
,
location
.
origin
+
"/#"
+
this
.
$route
.
path
+
query
);
if
(
this
.
userAccount
!=
null
&&
this
.
userAccount
!=
"null"
&&
...
...
@@ -1009,8 +889,7 @@ export default {
!
this
.
isUserSendLongTimeSystemMessage
&&
Date
.
now
()
-
lastCallBackMessageTime
>=
1000
*
60
*
5
)
{
const
IM
=
this
.
$mimcInstance
;
var
message
=
IM
.
createLocalMessage
(
var
message
=
this
.
$mimcInstance
.
createLocalMessage
(
"system"
,
this
.
account
,
"您已超过5分钟未回复消息,系统3分钟后将结束对话"
...
...
@@ -1034,8 +913,7 @@ export default {
loogTimeWaitText
.
trim
()
!=
""
&&
Date
.
now
()
-
lastCallBackMessageTime
>=
1000
*
60
*
2
)
{
const
IM
=
this
.
$mimcInstance
;
var
message
=
IM
.
createLocalMessage
(
var
message
=
this
.
$mimcInstance
.
createLocalMessage
(
"text"
,
this
.
account
,
loogTimeWaitText
...
...
@@ -1054,9 +932,8 @@ export default {
return
;
}
if
(
this
.
searchHandshakeTimer
)
clearTimeout
(
this
.
searchHandshakeTimer
);
const
IM
=
this
.
$mimcInstance
;
this
.
searchHandshakeTimer
=
setTimeout
(()
=>
{
IM
.
sendMessage
(
"search_knowledge"
,
this
.
robotAccount
,
this
.
chatValue
);
this
.
$mimcInstance
.
sendMessage
(
"search_knowledge"
,
this
.
robotAccount
,
this
.
chatValue
);
this
.
searchHandshakeTimer
=
null
;
},
500
);
},
...
...
@@ -1126,40 +1003,6 @@ export default {
</
script
>
<
style
lang=
"stylus"
>
body
{
min-width
:
240px
;
overflow
:
hidden
;
height
:
100vh
;
background-color
:
#f3f3f3
;
}
.mint-header.is-fixed
{
height
:
50px
!important
;
background
:
-webkit-linear-gradient
(
to
right
,
#26a2ff
,
#736cde
);
background
:
-o-linear-gradient
(
to
right
,
#26a2ff
,
#736cde
);
background
:
-moz-linear-gradient
(
to
right
,
#26a2ff
,
#736cde
);
background
:
linear-gradient
(
to
right
,
#26a2ff
,
#736cde
);
.mint-header-title
{
font-size
:
15px
;
}
}
.mint-header
,
.mint-tabbar
{
min-width
:
240px
;
z-index
:
999999999
!important
;
}
.mint-header
.is-right
{
img
{
width
:
25px
;
}
}
.mint-header
.mint-button
.mintui
{
font-size
:
23px
!important
;
}
.mint-tabbar
{
z-index
:
999999999
!important
;
background-color
:
#fff
!important
;
...
...
@@ -1198,11 +1041,12 @@ body {
.mini-im-loading
{
display
:
flex
;
min-width
:
240px
;
width
:
100%
;
position
:
fixed
;
height
100vh
top
:
0
;
left
:
0
;
z-index
:
9
;
right
:
0
;
background-color
:
#fff
!important
;
margin
:
auto
;
...
...
@@ -1456,7 +1300,7 @@ body {
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
z-index
:
9
;
z-index
:
8
;
span
{
color
:
#999
;
...
...
ui/kefu_client/src/views/workorder.vue
View file @
825ca73b
<
template
>
<div
class=
"container"
>
<mt-header
v-if=
"isShowHeader"
fixed
:title=
"isInputPongIng ? inputPongIngString : '在线客服'
"
>
<mt-header
v-if=
"isShowHeader"
fixed
title=
"工单
"
>
<div
slot=
"left"
>
<mt-button
@
click=
"
back
"
icon=
"back"
></mt-button>
<mt-button
@
click=
"
$router.go(-1)
"
icon=
"back"
></mt-button>
</div>
<mt-button
@
click=
"headRightBtn"
slot=
"right"
>
<img
title=
"人工客服"
v-if=
"!isArtificial"
src=
"http://qiniu.cmp520.com/kefu_icon_2000.png"
alt
/>
<span
v-else
>
结束会话
</span>
<mt-button
@
click=
"$router.push('/workorder/create')"
slot=
"right"
>
<span>
创建工单
</span>
</mt-button>
</mt-header>
</div>
</
template
>
<
script
>
import
{
mapGetters
}
from
'vuex'
export
default
{
name
:
"workorder"
,
components
:
{},
data
()
{
return
{};
},
computed
:
{
...
mapGetters
([
'isShowHeader'
])
},
mounted
()
{},
methods
:
{}
methods
:
{
}
};
</
script
>
<
style
lang=
"stylus"
scoped
>
...
...
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