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
e0bab0ee
authored
Mar 27, 2020
by
chenxianqi
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
update code
parent
b5c1cfa1
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
221 additions
and
81 deletions
controllers/base_controller.go
controllers/public_controller.go
main.go
routers/router.go
static/uploads/images/2020-03-27/2500171221313452.zip
static/uploads/images/2020-03-27/5325709067400059.jpg
task/app.go
ui/kefu_admin/src/App.vue
ui/kefu_admin/src/components/me-aside.vue
ui/kefu_admin/src/store/actions.js
ui/kefu_admin/src/store/getters.js
ui/kefu_admin/src/store/mutations.js
ui/kefu_admin/src/store/state.js
ui/kefu_admin/src/views/workbench/chat_window.vue
ui/kefu_admin/src/views/workbench/index.vue
ui/kefu_admin/src/views/workorder/index.vue
ui/kefu_admin/src/views/workorder/workorder-types-view.vue
ui/kefu_admin/src/views/workorder/workorder-view.vue
ui/kefu_client/src/main.js
ui/kefu_client/src/views/kefu.vue
ui/kefu_client/src/views/workorder.vue
ui/kefu_client/src/views/workorder_create.vue
ui/kefu_client/src/views/workorder_detail.vue
controllers/base_controller.go
View file @
e0bab0ee
...
@@ -60,9 +60,5 @@ func (c *BaseController) GetUserInfo() *models.User {
...
@@ -60,9 +60,5 @@ func (c *BaseController) GetUserInfo() *models.User {
return
nil
return
nil
}
}
var
userRepository
=
services
.
GetUserRepositoryInstance
()
var
userRepository
=
services
.
GetUserRepositoryInstance
()
user
:=
userRepository
.
GetUserWithToken
(
token
)
return
userRepository
.
GetUserWithToken
(
token
)
if
user
==
nil
{
logs
.
Warn
(
"GetUserInfo get current user info error------------用户效验失败!"
)
}
return
user
}
}
controllers/public_controller.go
View file @
e0bab0ee
...
@@ -103,11 +103,6 @@ func (c *PublicController) Register() {
...
@@ -103,11 +103,6 @@ func (c *PublicController) Register() {
/// old user
/// old user
if
user
!=
nil
{
if
user
!=
nil
{
// The last login address is inconsistent with this time and the token is not empty
// if user.Token != "" && user.RemoteAddr != "" && currentRemoteAddr != user.RemoteAddr {
// c.JSON(configs.ResponseFail, "注册失败,请稍等重试!", "")
// }
// fetchResult
// fetchResult
fetchResult
,
fetchError
=
utils
.
CreateMiMcToken
(
strconv
.
FormatInt
(
user
.
ID
,
10
))
fetchResult
,
fetchError
=
utils
.
CreateMiMcToken
(
strconv
.
FormatInt
(
user
.
ID
,
10
))
if
err
:=
json
.
Unmarshal
([]
byte
(
fetchResult
),
&
imTokenDto
);
err
!=
nil
{
if
err
:=
json
.
Unmarshal
([]
byte
(
fetchResult
),
&
imTokenDto
);
err
!=
nil
{
...
@@ -211,6 +206,7 @@ func (c *PublicController) Read() {
...
@@ -211,6 +206,7 @@ func (c *PublicController) Read() {
if
err
==
nil
{
if
err
==
nil
{
readCount
=
0
readCount
=
0
}
}
c
.
JSON
(
configs
.
ResponseSucess
,
"查询成功!"
,
readCount
)
c
.
JSON
(
configs
.
ResponseSucess
,
"查询成功!"
,
readCount
)
}
}
...
@@ -369,6 +365,7 @@ func (c *PublicController) LastActivity() {
...
@@ -369,6 +365,7 @@ func (c *PublicController) LastActivity() {
// get user
// get user
user
:=
c
.
GetUserInfo
()
user
:=
c
.
GetUserInfo
()
// user
// user
if
user
!=
nil
{
if
user
!=
nil
{
_
,
err
:=
c
.
UserRepository
.
Update
(
user
.
ID
,
orm
.
Params
{
_
,
err
:=
c
.
UserRepository
.
Update
(
user
.
ID
,
orm
.
Params
{
...
@@ -390,6 +387,7 @@ func (c *PublicController) LastActivity() {
...
@@ -390,6 +387,7 @@ func (c *PublicController) LastActivity() {
}
}
c
.
JSON
(
configs
.
ResponseSucess
,
"上报成功!"
,
nil
)
c
.
JSON
(
configs
.
ResponseSucess
,
"上报成功!"
,
nil
)
}
}
// GetCompanyInfo get Company info
// GetCompanyInfo get Company info
...
...
main.go
View file @
e0bab0ee
...
@@ -19,7 +19,8 @@ import (
...
@@ -19,7 +19,8 @@ import (
func
initLog
()
{
func
initLog
()
{
if
isDev
:=
beego
.
AppConfig
.
String
(
"runmode"
);
isDev
==
"prod"
{
if
isDev
:=
beego
.
AppConfig
.
String
(
"runmode"
);
isDev
==
"prod"
{
_
=
logs
.
SetLogger
(
logs
.
AdapterFile
,
`{"filename":"project.log","level":7,"maxlines":0,"maxsize":0,"daily":true,"maxdays":10,"color":true}`
)
_
=
logs
.
SetLogger
(
logs
.
AdapterFile
,
`{"filename":"project.log","level":3,"maxlines":0,"maxsize":0,"daily":true,"maxdays":10,"color":true}`
)
beego
.
SetLevel
(
beego
.
LevelError
)
fmt
.
Print
(
"当前环境为生产环境"
)
fmt
.
Print
(
"当前环境为生产环境"
)
_
=
beego
.
BeeLogger
.
DelLogger
(
"console"
)
_
=
beego
.
BeeLogger
.
DelLogger
(
"console"
)
}
else
{
}
else
{
...
...
routers/router.go
View file @
e0bab0ee
...
@@ -32,9 +32,10 @@ func routers(prefix string) *beego.Namespace {
...
@@ -32,9 +32,10 @@ func routers(prefix string) *beego.Namespace {
beego
.
NSRouter
(
"/secret"
,
&
controllers
.
PublicController
{},
"get:UploadSecret"
),
beego
.
NSRouter
(
"/secret"
,
&
controllers
.
PublicController
{},
"get:UploadSecret"
),
beego
.
NSRouter
(
"/activity"
,
&
controllers
.
PublicController
{},
"get:LastActivity"
),
beego
.
NSRouter
(
"/activity"
,
&
controllers
.
PublicController
{},
"get:LastActivity"
),
// compatible
// compatible
v1
beego
.
NSRouter
(
"/activity/?:id"
,
&
controllers
.
PublicController
{},
"get:LastActivity"
),
beego
.
NSRouter
(
"/activity/?:id"
,
&
controllers
.
PublicController
{},
"get:LastActivity"
),
beego
.
NSRouter
(
"/clean_read/?:id"
,
&
controllers
.
PublicController
{},
"get:CleanRead"
),
beego
.
NSRouter
(
"/clean_read/?:id"
,
&
controllers
.
PublicController
{},
"get:CleanRead"
),
beego
.
NSRouter
(
"/read/?:id"
,
&
controllers
.
PublicController
{},
"get:Read"
),
beego
.
NSRouter
(
"/company"
,
&
controllers
.
PublicController
{},
"get:GetCompanyInfo"
),
beego
.
NSRouter
(
"/company"
,
&
controllers
.
PublicController
{},
"get:GetCompanyInfo"
),
beego
.
NSRouter
(
"/robot_info/:id"
,
&
controllers
.
PublicController
{},
"get:RobotInfo"
),
beego
.
NSRouter
(
"/robot_info/:id"
,
&
controllers
.
PublicController
{},
"get:RobotInfo"
),
...
...
static/uploads/images/2020-03-27/2500171221313452.zip
0 → 100644
View file @
e0bab0ee
No preview for this file type
static/uploads/images/2020-03-27/5325709067400059.jpg
0 → 100644
View file @
e0bab0ee
108 KB
task/app.go
View file @
e0bab0ee
...
@@ -14,12 +14,12 @@ import (
...
@@ -14,12 +14,12 @@ import (
func
appTask
()
{
func
appTask
()
{
// Task scheduling (will be executed once every 5 minute)
// Task scheduling (will be executed once every 5 minute)
checkOnLineTk
:=
toolbox
.
NewTask
(
"checkOnLine"
,
"0
*/5
* * * *"
,
func
()
error
{
checkOnLineTk
:=
toolbox
.
NewTask
(
"checkOnLine"
,
"0
/30 *
* * * *"
,
func
()
error
{
// timers
// timers
userOffLineUnixTimer
:=
time
.
Now
()
.
Unix
()
-
(
60
*
10
)
// User's last activity time T out online status rule
userOffLineUnixTimer
:=
time
.
Now
()
.
Unix
()
-
(
60
*
10
)
// User's last activity time T out online status rule
adminOffLineUnixTimer
:=
time
.
Now
()
.
Unix
()
-
(
60
*
30
)
// Final reply time
adminOffLineUnixTimer
:=
time
.
Now
()
.
Unix
()
-
(
60
*
30
)
// Final reply time
lastMessageUnixTimer
:=
time
.
Now
()
.
Unix
()
-
(
60
*
8
)
// Determine if the user will not use it for a certain period of time and force them to go offline
lastMessageUnixTimer
:=
time
.
Now
()
.
Unix
()
-
(
30
*
1
)
// Determine if the user will not use it for a certain period of time and force them to go offline
// user
// user
userOfflineCount
:=
services
.
GetUserRepositoryInstance
()
.
CheckUsersLoginTimeOutAndSetOffline
(
userOffLineUnixTimer
)
userOfflineCount
:=
services
.
GetUserRepositoryInstance
()
.
CheckUsersLoginTimeOutAndSetOffline
(
userOffLineUnixTimer
)
...
@@ -47,39 +47,24 @@ func appTask() {
...
@@ -47,39 +47,24 @@ func appTask() {
continue
continue
}
}
_lastBackAdmin
:=
services
.
GetAdminRepositoryInstance
()
.
GetAdmin
(
contact
.
LastAccount
)
robot
:=
robots
[
0
]
robot
:=
robots
[
0
]
// message body
//
timeout
message body
message
:=
models
.
Message
{}
message
:=
models
.
Message
{}
message
.
BizType
=
"timeout"
message
.
BizType
=
"timeout"
message
.
Read
=
0
message
.
Read
=
0
message
.
FromAccount
=
robot
.
ID
message
.
FromAccount
=
robot
.
ID
message
.
Timestamp
=
time
.
Now
()
.
Unix
()
message
.
Timestamp
=
time
.
Now
()
.
Unix
()
message
.
Payload
=
"您长时间未回复,本次会话超时了"
message
.
Payload
=
"由于双方长时间未互动,本次会话结束"
if
_lastBackAdmin
==
nil
{
message
.
Payload
=
"客服长时间未回复,会话结束,您可以重新发起人工"
}
message
.
ToAccount
=
contact
.
FromAccount
message
.
ToAccount
=
contact
.
FromAccount
var
messageString
string
var
messageString
string
messageString
=
utils
.
InterfaceToString
(
message
)
messageString
=
utils
.
InterfaceToString
(
message
)
utils
.
PushMessage
(
contact
.
FromAccount
,
messageString
)
utils
.
MessageInto
(
message
)
// Send a reminder message to customer service
message
.
FromAccount
=
robot
.
ID
message
.
ToAccount
=
contact
.
ToAccount
message
.
Payload
=
"用户长时间无应答,会话结束"
if
_lastBackAdmin
==
nil
{
message
.
Read
=
1
message
.
Payload
=
"您长时间未回复客户,会话结束"
}
messageString
=
utils
.
InterfaceToString
(
message
)
utils
.
PushMessage
(
contact
.
ToAccount
,
messageString
)
utils
.
PushMessage
(
contact
.
ToAccount
,
messageString
)
utils
.
PushMessage
(
contact
.
FromAccount
,
messageString
)
utils
.
MessageInto
(
message
)
utils
.
MessageInto
(
message
)
// Message after timeout
// Message after timeout
if
robot
.
TimeoutText
!=
""
&&
_lastBackAdmin
!=
nil
{
if
robot
.
TimeoutText
!=
""
{
message
.
FromAccount
=
robot
.
ID
message
.
FromAccount
=
robot
.
ID
message
.
ToAccount
=
contact
.
FromAccount
message
.
ToAccount
=
contact
.
FromAccount
message
.
BizType
=
"text"
message
.
BizType
=
"text"
...
...
ui/kefu_admin/src/App.vue
View file @
e0bab0ee
...
@@ -24,12 +24,14 @@ export default {
...
@@ -24,12 +24,14 @@ export default {
this
.
$store
.
dispatch
(
'ON_GET_UPLOADS_CONFIG'
)
this
.
$store
.
dispatch
(
'ON_GET_UPLOADS_CONFIG'
)
this
.
$store
.
dispatch
(
'ON_GET_ROBOTS'
)
this
.
$store
.
dispatch
(
'ON_GET_ROBOTS'
)
this
.
$store
.
dispatch
(
'ON_GET_CONTACTS'
)
this
.
$store
.
dispatch
(
'ON_GET_CONTACTS'
)
this
.
$store
.
dispatch
(
'ON_GET_WORKORDER_COUNTS'
)
setInterval
(()
=>
this
.
$store
.
dispatch
(
'ON_GET_WORKORDER_COUNTS'
),
30000
)
// 一分钟上报一次我的活动时间
// 一分钟上报一次我的活动时间
this
.
upLastActivity
()
this
.
upLastActivity
()
// 获取会话表
// 获取会话表
setInterval
(()
=>
this
.
getContacts
(),
2000
)
this
.
getContacts
(
)
// Mimc 初始化
// Mimc 初始化
this
.
initMimc
()
this
.
initMimc
()
...
...
ui/kefu_admin/src/components/me-aside.vue
View file @
e0bab0ee
...
@@ -24,14 +24,14 @@
...
@@ -24,14 +24,14 @@
</div>
</div>
</el-badge>
</el-badge>
</el-menu-item>
</el-menu-item>
<
!--
<
el-menu-item
index=
"/workorder"
>
<el-menu-item
index=
"/workorder"
>
<el-badge
:hidden=
"$store.getters.
readCount == 0"
:value=
"$store.getters.readCount
"
:max=
"99"
style=
"width: 100%;"
>
<el-badge
:hidden=
"$store.getters.
workOrderCounts.status0 == 0"
:value=
"$store.getters.workOrderCounts.status0
"
:max=
"99"
style=
"width: 100%;"
>
<div>
<div>
<i
class=
"el-icon-tickets"
></i>
<i
class=
"el-icon-tickets"
></i>
<span
slot=
"title"
>
工单管理
</span>
<span
slot=
"title"
>
工单管理
</span>
</div>
</div>
</el-badge>
</el-badge>
</el-menu-item>
-->
</el-menu-item>
<el-menu-item
index=
"/knowledge"
>
<el-menu-item
index=
"/knowledge"
>
<i
class=
"el-icon-reading"
></i>
<i
class=
"el-icon-reading"
></i>
<span
slot=
"title"
>
知识库
</span>
<span
slot=
"title"
>
知识库
</span>
...
@@ -58,12 +58,12 @@
...
@@ -58,12 +58,12 @@
</el-menu-item>
</el-menu-item>
</el-menu>
</el-menu>
<
!--
<
div
class=
"fix-bottom"
>
<div
class=
"fix-bottom"
>
<a
title=
"去给作者Star"
target=
"_blank"
href=
"https://github.com/chenxianqi/kefu_server.git"
>
<a
title=
"去给作者Star"
target=
"_blank"
href=
"https://github.com/chenxianqi/kefu_server.git"
>
<svg
class=
"github-logo"
height=
"23"
viewBox=
"0 0 16 16"
version=
"1.1"
width=
"23"
aria-hidden=
"true"
><path
fill=
"#fff"
fill-rule=
"evenodd"
d=
"M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"
></path></svg>
<svg
class=
"github-logo"
height=
"23"
viewBox=
"0 0 16 16"
version=
"1.1"
width=
"23"
aria-hidden=
"true"
><path
fill=
"#fff"
fill-rule=
"evenodd"
d=
"M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"
></path></svg>
<span>
Github
</span>
<span>
Github
</span>
</a>
</a>
</div>
-->
</div>
</el-aside>
</el-aside>
</
template
>
</
template
>
<
script
>
<
script
>
...
...
ui/kefu_admin/src/store/actions.js
View file @
e0bab0ee
...
@@ -76,5 +76,12 @@ export default {
...
@@ -76,5 +76,12 @@ export default {
.
catch
(()
=>
{
.
catch
(()
=>
{
this
.
loading
=
false
this
.
loading
=
false
});
});
},
// 获取工单系统counts
ON_GET_WORKORDER_COUNTS
(
context
){
axios
.
get
(
'/workorder/counts'
)
.
then
(
response
=>
{
context
.
commit
(
'onChangeWorkOrderCounts'
,
response
.
data
.
data
)
})
}
}
}
}
\ No newline at end of file
ui/kefu_admin/src/store/getters.js
View file @
e0bab0ee
...
@@ -75,4 +75,8 @@ export default {
...
@@ -75,4 +75,8 @@ export default {
workbenchBgColor
(
state
){
workbenchBgColor
(
state
){
return
state
.
workbenchBgColor
return
state
.
workbenchBgColor
},
},
// 工单统计
workOrderCounts
(
state
){
return
state
.
workOrderCounts
}
}
}
\ No newline at end of file
ui/kefu_admin/src/store/mutations.js
View file @
e0bab0ee
...
@@ -75,5 +75,9 @@ export default {
...
@@ -75,5 +75,9 @@ export default {
// 是否是登陆状态
// 是否是登陆状态
onIsLogin
(
state
,
isLogin
){
onIsLogin
(
state
,
isLogin
){
state
.
isLogin
=
isLogin
state
.
isLogin
=
isLogin
}
},
// 工单统计
onChangeWorkOrderCounts
(
state
,
counts
){
state
.
workOrderCounts
=
counts
},
}
}
\ No newline at end of file
ui/kefu_admin/src/store/state.js
View file @
e0bab0ee
This diff is collapsed.
Click to expand it.
ui/kefu_admin/src/views/workbench/chat_window.vue
View file @
e0bab0ee
...
@@ -74,7 +74,6 @@
...
@@ -74,7 +74,6 @@
<em>
{{
$formatFromNowDate
(
item
.
timestamp
)
}}
</em>
<em>
{{
$formatFromNowDate
(
item
.
timestamp
)
}}
</em>
<span
v-if=
"item.to_account != adminInfo.id"
>
你结束了会话
</span>
<span
v-if=
"item.to_account != adminInfo.id"
>
你结束了会话
</span>
<span
v-else
>
对方结束了会话
</span>
<span
v-else
>
对方结束了会话
</span>
<em>
{{
$formatFromNowDate
(
item
.
timestamp
)
}}
</em>
</div>
</div>
</
template
>
</
template
>
...
...
ui/kefu_admin/src/views/workbench/index.vue
View file @
e0bab0ee
...
@@ -632,7 +632,7 @@ export default {
...
@@ -632,7 +632,7 @@ export default {
});
});
}
}
// 是否是否当前会话消息
// 是否是否当前会话消息
if
(
message
.
from_account
!=
this
.
seviceCurrentUser
.
from_account
)
return
if
(
message
.
from_account
!=
this
.
seviceCurrentUser
.
from_account
&&
message
.
biz_type
!=
"timeout"
)
return
if
(
message
.
biz_type
==
'end'
){
if
(
message
.
biz_type
==
'end'
){
var
seviceCurrentUser
=
this
.
seviceCurrentUser
var
seviceCurrentUser
=
this
.
seviceCurrentUser
seviceCurrentUser
.
is_session_end
=
1
seviceCurrentUser
.
is_session_end
=
1
...
...
ui/kefu_admin/src/views/workorder/index.vue
View file @
e0bab0ee
...
@@ -5,17 +5,21 @@
...
@@ -5,17 +5,21 @@
<span>
<span>
<i
class=
"el-icon-tickets"
></i>
<i
class=
"el-icon-tickets"
></i>
<span
slot=
"title"
>
工单管理
</span>
<span
slot=
"title"
>
工单管理
</span>
<span
style=
"font-size:15px;margin-left: 30px;color:#e7a646"
>
当前有
<span
style=
"font-size:15px;margin-left: 30px;color:#e7a646"
>
<strong
style=
"color: #f56c6c"
>
5
</strong>
<template
v-if=
"workOrderCounts.status0 > 0"
>
条待处理, 和
<strong
style=
"color: #f56c6c"
>
8
</strong>
当前有
<strong
style=
"color: #f56c6c"
>
{{
workOrderCounts
.
status0
}}
</strong>
条待处理,
条待回复工单
</span>
</
template
>
<
template
v-if=
"workOrderCounts.status2 > 0"
>
<strong
style=
"color: #f56c6c"
>
{{
workOrderCounts
.
status2
}}
</strong>
条待回复工单
</
template
>
</span>
</span>
</span>
<div>
<div>
<el-button
size=
"mini"
>
分类设置
</el-button>
<el-button
size=
"mini"
@
click=
"isShowTypesView = true"
>
分类设置
</el-button>
</div>
</div>
</div>
</div>
<el-divider
/>
<el-divider
/>
<
div
class=
"container-box
"
>
<
el-row
class=
"container-box"
type=
"flex"
justify=
"space-between
"
>
<div
class=
"menu"
>
<div
class=
"menu"
>
<el-tabs
@
tab-click=
"tabsChange"
tab-position=
"left"
style=
"width:200px;height: 80vh;"
>
<el-tabs
@
tab-click=
"tabsChange"
tab-position=
"left"
style=
"width:200px;height: 80vh;"
>
<
template
size=
"small"
v-for=
"item in workorderTypes"
border
>
<
template
size=
"small"
v-for=
"item in workorderTypes"
border
>
...
@@ -29,14 +33,19 @@
...
@@ -29,14 +33,19 @@
<el-table-column
prop=
"title"
label=
"工单标题"
></el-table-column>
<el-table-column
prop=
"title"
label=
"工单标题"
></el-table-column>
<el-table-column
prop=
"status"
label=
"当前状态"
>
<el-table-column
prop=
"status"
label=
"当前状态"
>
<
template
slot-scope=
"scope"
>
<
template
slot-scope=
"scope"
>
<el-tag
type=
"warning"
v-if=
"scope.row.status == 0"
>
等待客服处理
</el-tag>
<template
v-if=
"workorderTypes.length-1 == tabIndex"
>
<el-tag
type=
"warning"
v-if=
"scope.row.status == 2"
>
等待客服回复
</el-tag>
<span
style=
"color:#f56c6b"
>
已删除
</span>
<el-tag
type=
"success"
v-if=
"scope.row.status == 1"
>
已有客服回复
</el-tag>
</
template
>
<
template
v-else
>
<el-tag
type=
"danger"
v-if=
"scope.row.status == 0"
>
待客服处理
</el-tag>
<el-tag
type=
"warning"
v-if=
"scope.row.status == 2"
>
待客服回复
</el-tag>
<el-tag
type=
"success"
v-if=
"scope.row.status == 1"
>
客服已回复
</el-tag>
<el-tag
type=
"info"
v-if=
"scope.row.status == 3"
>
工单已结束
</el-tag>
<el-tag
type=
"info"
v-if=
"scope.row.status == 3"
>
工单已结束
</el-tag>
</
template
>
</
template
>
</template>
</el-table-column>
</el-table-column>
<el-table-column
prop=
"u_nickname"
label=
"用户
(发布者)
"
></el-table-column>
<el-table-column
prop=
"u_nickname"
label=
"用户"
></el-table-column>
<el-table-column
prop=
"a_nickname"
label=
"最
后回复者
(客服)"
>
<el-table-column
prop=
"a_nickname"
label=
"最
近处理
(客服)"
>
<
template
slot-scope=
"scope"
>
<
template
slot-scope=
"scope"
>
{{
scope
.
row
.
a_nickname
||
'-----'
}}
{{
scope
.
row
.
a_nickname
||
'-----'
}}
</
template
>
</
template
>
...
@@ -63,22 +72,27 @@
...
@@ -63,22 +72,27 @@
></el-pagination>
></el-pagination>
</el-row>
</el-row>
</div>
</div>
</
div
>
</
el-row
>
<WorkOrderView
:workorderTypes=
"workorderTypes"
:prop=
"showWorkOrder"
v-model=
"isShowWorkOrderView"
/>
<WorkOrderView
:workorderTypes=
"workorderTypes"
:prop=
"showWorkOrder"
v-model=
"isShowWorkOrderView"
/>
<WorkOrderTypesView
:workorderTypes=
"workorderTypes"
v-model=
"isShowTypesView"
/>
</div>
</div>
</template>
</template>
<
script
>
<
script
>
import
axios
from
"axios"
;
import
axios
from
"axios"
;
import
WorkOrderView
from
"./workorder-view"
import
WorkOrderView
from
"./workorder-view"
import
WorkOrderTypesView
from
"./workorder-types-view"
import
{
mapGetters
}
from
'vuex'
export
default
{
export
default
{
name
:
"workorder-index"
,
name
:
"workorder-index"
,
components
:
{
components
:
{
WorkOrderView
WorkOrderView
,
WorkOrderTypesView
},
},
data
()
{
data
()
{
return
{
return
{
loading
:
true
,
loading
:
true
,
isShowWorkOrderView
:
false
,
isShowWorkOrderView
:
false
,
isShowTypesView
:
false
,
showWorkOrder
:
{},
showWorkOrder
:
{},
tableData
:
{
tableData
:
{
list
:
[],
list
:
[],
...
@@ -105,8 +119,14 @@ export default {
...
@@ -105,8 +119,14 @@ export default {
if
(
this
.
tabIndex
==
this
.
workorderTypes
.
length
-
1
&&
this
.
workorderTypes
.
length
>
1
){
if
(
this
.
tabIndex
==
this
.
workorderTypes
.
length
-
1
&&
this
.
workorderTypes
.
length
>
1
){
return
'0,1,2,3'
return
'0,1,2,3'
}
}
return
"0,1,2"
if
(
this
.
tabIndex
==
this
.
workorderTypes
.
length
-
2
&&
this
.
workorderTypes
.
length
>
1
){
return
'3'
}
}
return
"0,1,2"
},
...
mapGetters
([
"workOrderCounts"
,
])
},
},
created
()
{
created
()
{
this
.
getWorkorderList
();
this
.
getWorkorderList
();
...
@@ -161,12 +181,12 @@ export default {
...
@@ -161,12 +181,12 @@ export default {
}
}
this
.
workorderTypes
.
push
({
this
.
workorderTypes
.
push
({
"id"
:
-
1
,
"id"
:
-
1
,
"count"
:
0
,
"count"
:
this
.
workOrderCounts
.
status3
,
"title"
:
"已结单"
"title"
:
"已结单"
})
})
this
.
workorderTypes
.
push
({
this
.
workorderTypes
.
push
({
"id"
:
-
2
,
"id"
:
-
2
,
"count"
:
0
,
"count"
:
this
.
workOrderCounts
.
delete_count
,
"title"
:
"回收站"
"title"
:
"回收站"
})
})
})
})
...
@@ -208,12 +228,12 @@ export default {
...
@@ -208,12 +228,12 @@ export default {
}
}
}
}
.container-box
{
.container-box
{
display
flex
.menu{
.menu{
flex-shrink
:
0
;
flex-shrink
:
0
;
width
180px;
width
180px;
}
}
.table-content
{
.table-content
{
width
500px;
flex-grow
1
flex-grow
1
}
}
}
}
...
...
ui/kefu_admin/src/views/workorder/workorder-types-view.vue
0 → 100644
View file @
e0bab0ee
<
template
>
<div
class=
"workorder-view"
v-show=
"value"
>
<div
class=
"mask"
@
dblclick=
"close"
></div>
<div
class=
"content-box"
>
<el-row
type=
"flex"
class=
"title"
>
<span><i
class=
"el-icon-tickets"
></i>
分类设置
</span>
<div>
<el-button
size=
"mini"
type=
"primary"
>
添加分类
</el-button>
</div>
</el-row
>
<span
class=
"close"
@
click=
"close"
>
<i
class=
"el-icon-close"
></i>
</span>
<div
class=
"content"
>
<div
class=
"scroll"
>
</div>
</div>
</div>
</div>
</
template
>
<
script
>
export
default
{
name
:
"workorder-view"
,
data
()
{
return
{
isSubmit
:
false
,
comments
:
[],
request
:
{
source
:
""
,
content
:
""
}
};
},
props
:
{
value
:
{
default
:
false
,
type
:
Boolean
},
workorderTypes
:
Array
},
created
()
{
this
.
comments
=
[];
},
computed
:
{
isShowAside
()
{
return
this
.
$store
.
state
.
isShowAside
;
},
},
methods
:
{
// 按钮操作
close
()
{
this
.
$emit
(
"input"
,
false
);
},
},
watch
:
{
}
};
</
script
>
<
style
scoped
lang=
"stylus"
>
.workorder-view
{
width
:
100vw
;
height
:
100vh
;
position
:
fixed
;
right
:
0
;
top
:
0px
;
left
:
0px
;
background-color
:
rgba
(
0
,
0
,
0
,
0.8
);
z-index
:
9
;
.mask
{
width
:
100%
;
height
:
100%
;
}
.content-box
{
width
:
400px
;
height
:
100%
;
background-color
:
#fff
;
position
:
fixed
;
right
:
0px
;
margin
:
0
auto
;
top
:
0px
;
overflow
:
hidden
;
padding-top
:
40px
;
padding-bottom
:
135px
;
box-sizing
:
border-box
;
.title
{
width
:
100%
;
height
:
60px
;
border-bottom
:
1px
solid
#ddd
;
position
:
absolute
;
top
:
0
;
left
:
0
;
padding
0
10px
background-color
:
#fff
;
box-sizing
:
border-box
;
&>span{
width
260px;
}
align-content
center
align-items
center
}
.buttons
{
position
:
absolute
;
top
:
5px
;
right
:
50px
;
}
.close
{
position
:
absolute
;
top
:
15px
;
right
:
5px
;
font-size
:
25px
;
color
:
#ccc
;
cursor
:
pointer
;
}
}
}
</
style
>
ui/kefu_admin/src/views/workorder/workorder-view.vue
View file @
e0bab0ee
<
template
>
<
template
>
<div
class=
"workorder-view"
:class=
"
{'is-show-aside': !isShowAside}"
v-show="value">
<div
class=
"workorder-view"
v-show=
"value"
>
<div
class=
"mask"
@
dblclick=
"close"
></div>
<div
class=
"mask"
@
dblclick=
"close"
></div>
<transition
name=
"el-zoom-in-bottom"
>
<transition
name=
"el-zoom-in-bottom"
>
<div
class=
"content-box"
:class=
"
{'padding-bottom30': showData.status == 3}" v-show="value">
<div
class=
"content-box"
:class=
"
{'padding-bottom30': showData.status == 3}" v-show="value">
...
@@ -50,9 +50,9 @@
...
@@ -50,9 +50,9 @@
<div
class=
"form-line"
>
<div
class=
"form-line"
>
<span
class=
"lable"
>
状态:
</span>
<span
class=
"lable"
>
状态:
</span>
<div
class=
"con"
>
<div
class=
"con"
>
<span
style=
"color:#
e6a23c;"
v-if=
"showData.status == 0"
>
等
待客服处理
</span>
<span
style=
"color:#
f56c6b"
v-if=
"showData.status == 0"
>
待客服处理
</span>
<span
style=
"color:#e6a23c;"
v-if=
"showData.status == 2"
>
等
待客服回复
</span>
<span
style=
"color:#e6a23c;"
v-if=
"showData.status == 2"
>
待客服回复
</span>
<span
style=
"color:#67c23a;"
v-if=
"showData.status == 1"
>
已有客服
回复
</span>
<span
style=
"color:#67c23a;"
v-if=
"showData.status == 1"
>
客服已
回复
</span>
<span
style=
"color:#909399;"
v-if=
"showData.status == 3"
>
工单已结束
</span>
<span
style=
"color:#909399;"
v-if=
"showData.status == 3"
>
工单已结束
</span>
</div>
</div>
</div>
</div>
...
@@ -295,7 +295,7 @@ export default {
...
@@ -295,7 +295,7 @@ export default {
var
fileType
=
src
.
substr
(
src
.
lastIndexOf
(
"."
)
+
1
);
var
fileType
=
src
.
substr
(
src
.
lastIndexOf
(
"."
)
+
1
);
if
(
"jpg,jpeg,png,JPG,JPEG,PNG"
.
indexOf
(
fileType
)
!=
-
1
)
{
if
(
"jpg,jpeg,png,JPG,JPEG,PNG"
.
indexOf
(
fileType
)
!=
-
1
)
{
html
=
html
=
"
<
br
><
img
style
=
'max-width:45%'
preview
=
'1'
src
=
'" +
"
<
br
><
img
style
=
'max-width:45%
;margin-top:5px;
'
preview
=
'1'
src
=
'" +
fullPath +
fullPath +
"'
/>
";
"'
/>
";
} else {
} else {
...
@@ -561,14 +561,6 @@ export default {
...
@@ -561,14 +561,6 @@ export default {
}
}
}
}
}
}
&
.is-show-aside
{
left
:
0
;
.content
{
left
:
0px
;
}
}
}
}
</
style
>
</
style
>
ui/kefu_client/src/main.js
View file @
e0bab0ee
...
@@ -18,10 +18,14 @@ axios.defaults.baseURL = '/api'
...
@@ -18,10 +18,14 @@ axios.defaults.baseURL = '/api'
// axios添加请求拦截器
// axios添加请求拦截器
axios
.
interceptors
.
request
.
use
(
function
(
config
)
{
axios
.
interceptors
.
request
.
use
(
function
(
config
)
{
if
(
config
.
url
.
indexOf
(
"https://restapi.amap.com/v3/ip"
)
!=
-
1
){
return
config
;
}
const
token
=
localStorage
.
getItem
(
'Token'
)
||
""
const
token
=
localStorage
.
getItem
(
'Token'
)
||
""
config
.
headers
=
Object
.
assign
({},
{
config
.
headers
=
Object
.
assign
({},
{
'Token'
:
token
,
'Token'
:
token
,
},
config
.
headers
)
},
config
.
headers
)
return
config
;
return
config
;
},
function
(
error
)
{
},
function
(
error
)
{
// eslint-disable-next-line no-console
// eslint-disable-next-line no-console
...
...
ui/kefu_client/src/views/kefu.vue
View file @
e0bab0ee
...
@@ -193,14 +193,14 @@
...
@@ -193,14 +193,14 @@
<span
class=
"expression-btn"
@
click=
"showEmoji = !showEmoji"
>
<span
class=
"expression-btn"
@
click=
"showEmoji = !showEmoji"
>
<img
src=
"../assets/expression.png"
alt
/>
<img
src=
"../assets/expression.png"
alt
/>
</span>
</span>
<
!-- <
span
<span
class=
"workorder-btn"
class=
"workorder-btn"
:class=
"{'show-header': !isShowHeader && isMobile}"
:class=
"{'show-header': !isShowHeader && isMobile}"
@
click=
"$router.push('/workorder')"
@
click=
"$router.push('/workorder')"
>
>
<img
src=
"../assets/workorder.png"
/>
<img
src=
"../assets/workorder.png"
/>
<i>
工单
</i>
<i>
工单
</i>
</span>
-->
</span>
<span
<span
v-show=
"isMobile && !isShowHeader"
v-show=
"isMobile && !isShowHeader"
@
click=
"headRightBtn"
@
click=
"headRightBtn"
...
@@ -340,6 +340,9 @@ export default {
...
@@ -340,6 +340,9 @@ export default {
return
return
}
}
// 关闭loading
this
.
$store
.
commit
(
"updateState"
,
{
isShowPageLoading
:
false
})
// handelEvent
// handelEvent
this
.
handelEvent
();
this
.
handelEvent
();
...
@@ -355,9 +358,6 @@ export default {
...
@@ -355,9 +358,6 @@ export default {
this
.
scrollIntoBottom
();
this
.
scrollIntoBottom
();
// 关闭loading
setTimeout
(()
=>
this
.
$store
.
commit
(
"updateState"
,
{
isShowPageLoading
:
false
}),
500
)
// 计算客服最后回复时间
// 计算客服最后回复时间
this
.
onServciceLastMessageTimeNotCallBack
();
this
.
onServciceLastMessageTimeNotCallBack
();
...
@@ -593,7 +593,6 @@ export default {
...
@@ -593,7 +593,6 @@ export default {
// 接收消息
// 接收消息
receiveP2PMsg
(
message
)
{
receiveP2PMsg
(
message
)
{
console
.
log
(
message
);
console
.
log
(
message
);
if
(
message
.
biz_type
==
"contacts"
)
return
// 是否是转接客服消息
// 是否是转接客服消息
if
(
message
.
biz_type
==
"transfer"
)
{
if
(
message
.
biz_type
==
"transfer"
)
{
this
.
$store
.
commit
(
"updateState"
,
{
this
.
$store
.
commit
(
"updateState"
,
{
...
...
ui/kefu_client/src/views/workorder.vue
View file @
e0bab0ee
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
<div
class=
"list"
:class=
"
{'hide-header': !isShowHeader}">
<div
class=
"list"
:class=
"
{'hide-header': !isShowHeader}">
<div
class=
"no-data"
v-if=
"workorders.length
<
=
0
"
>
<div
class=
"no-data"
v-if=
"workorders.length
<
=
0
"
>
<img
src=
"../assets/workorder.png"
alt=
""
>
<img
src=
"../assets/workorder.png"
alt=
""
>
<div>
您
还没有发布
过工单~
</div>
<div>
您
没有发布相关
过工单~
</div>
</div>
</div>
<ul
v-else
>
<ul
v-else
>
<template
v-for=
"(item,index) in workorders"
>
<template
v-for=
"(item,index) in workorders"
>
...
...
ui/kefu_client/src/views/workorder_create.vue
View file @
e0bab0ee
...
@@ -130,7 +130,7 @@ export default {
...
@@ -130,7 +130,7 @@ export default {
var
fullPath
=
self
.
uploadToken
.
host
+
"/"
+
src
;
var
fullPath
=
self
.
uploadToken
.
host
+
"/"
+
src
;
var
fileType
=
src
.
substr
(
src
.
lastIndexOf
(
"."
)
+
1
);
var
fileType
=
src
.
substr
(
src
.
lastIndexOf
(
"."
)
+
1
);
if
(
"jpg,jpeg,png,JPG,JPEG,PNG"
.
indexOf
(
fileType
)
!=
-
1
)
{
if
(
"jpg,jpeg,png,JPG,JPEG,PNG"
.
indexOf
(
fileType
)
!=
-
1
)
{
html
=
"
<
br
><
img
style
=
'max-width:45%'
preview
=
'1'
src
=
'" + fullPath + "'
/>
"
html
=
"
<
br
><
img
style
=
'max-width:45%
;margin-top:5px;
'
preview
=
'1'
src
=
'" + fullPath + "'
/>
"
}else{
}else{
html = "
<
br
><
img
style
=
'width:20px;height:20px;top:3px; right:3px;position: relative;'
preview
=
'1'
src
=
'http://qiniu.cmp520.com/fj.png'
/>
"
html = "
<
br
><
img
style
=
'width:20px;height:20px;top:3px; right:3px;position: relative;'
preview
=
'1'
src
=
'http://qiniu.cmp520.com/fj.png'
/>
"
html += "
<
a
target
=
'_blank'
style
=
'color: #2e9dfc;'
href
=
'"+fullPath+"'
>
下载附件
<
/a>
"
html += "
<
a
target
=
'_blank'
style
=
'color: #2e9dfc;'
href
=
'"+fullPath+"'
>
下载附件
<
/a>
"
...
...
ui/kefu_client/src/views/workorder_detail.vue
View file @
e0bab0ee
...
@@ -219,7 +219,7 @@ export default {
...
@@ -219,7 +219,7 @@ export default {
var
fullPath
=
self
.
uploadToken
.
host
+
"/"
+
src
;
var
fullPath
=
self
.
uploadToken
.
host
+
"/"
+
src
;
var
fileType
=
src
.
substr
(
src
.
lastIndexOf
(
"."
)
+
1
);
var
fileType
=
src
.
substr
(
src
.
lastIndexOf
(
"."
)
+
1
);
if
(
"jpg,jpeg,png,JPG,JPEG,PNG"
.
indexOf
(
fileType
)
!=
-
1
)
{
if
(
"jpg,jpeg,png,JPG,JPEG,PNG"
.
indexOf
(
fileType
)
!=
-
1
)
{
html
=
"
<
br
><
img
style
=
'max-width:45%'
preview
=
'1'
src
=
'" + fullPath + "'
/>
"
html
=
"
<
br
><
img
style
=
'max-width:45%
;margin-top:5px;
'
preview
=
'1'
src
=
'" + fullPath + "'
/>
"
}else{
}else{
html = "
<
br
><
img
style
=
'width:20px;height:20px;top:3px; right:3px;position: relative;'
preview
=
'1'
src
=
'http://qiniu.cmp520.com/fj.png'
/>
"
html = "
<
br
><
img
style
=
'width:20px;height:20px;top:3px; right:3px;position: relative;'
preview
=
'1'
src
=
'http://qiniu.cmp520.com/fj.png'
/>
"
html += "
<
a
target
=
'_blank'
style
=
'color: #2e9dfc;'
href
=
'"+fullPath+"'
>
下载附件
<
/a>
"
html += "
<
a
target
=
'_blank'
style
=
'color: #2e9dfc;'
href
=
'"+fullPath+"'
>
下载附件
<
/a>
"
...
...
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