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
e3a7f5bd
authored
Mar 22, 2020
by
chenxianqi
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
update code
parent
825ca73b
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
381 additions
and
33 deletions
controllers/public_controller.go
routers/router.go
ui/kefu_client/plugins/help.js
ui/kefu_client/plugins/mimc.js
ui/kefu_client/src/App.vue
ui/kefu_client/src/assets/workorder.png
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/state.js
ui/kefu_client/src/views/kefu.vue
ui/kefu_client/src/views/workorder.vue
ui/kefu_client/src/views/workorder_detail.vue
controllers/public_controller.go
View file @
e3a7f5bd
...
...
@@ -601,6 +601,13 @@ func (c *PublicController) CreateWorkOrder() {
c
.
JSON
(
configs
.
ResponseFail
,
err
.
Message
,
nil
)
}
}
// type is exist?
workOrderTypeRepository
:=
services
.
GetWorkOrderTypeRepositoryInstance
()
if
_
,
err
:=
workOrderTypeRepository
.
GetWorkOrderType
(
workOrder
.
CID
);
err
!=
nil
{
c
.
JSON
(
configs
.
ResponseFail
,
"创建失败,工单类型不存在~"
,
err
.
Error
())
}
workOrder
.
CreateAt
=
time
.
Now
()
.
Unix
()
workOrder
.
UID
=
user
.
ID
workOrderRepository
:=
services
.
GetWorkOrderRepositoryInstance
()
...
...
@@ -711,6 +718,20 @@ func (c *PublicController) GetWorkOrders() {
}
// GetWorkOrderTypes user get word order type all
func
(
c
*
PublicController
)
GetWorkOrderTypes
()
{
// get user
user
:=
c
.
GetUserInfo
()
if
user
==
nil
{
c
.
JSON
(
configs
.
ResponseFail
,
"查询失败!"
,
nil
)
}
workOrderTypeRepository
:=
services
.
GetWorkOrderTypeRepositoryInstance
()
workOrderTypes
:=
workOrderTypeRepository
.
GetWorkOrderTypes
()
c
.
JSON
(
configs
.
ResponseSucess
,
"查询成功!"
,
workOrderTypes
)
}
// GetWorkOrderComments get word order comments
func
(
c
*
PublicController
)
GetWorkOrderComments
()
{
...
...
routers/router.go
View file @
e3a7f5bd
...
...
@@ -3,7 +3,7 @@
// @Description kefu server APIs.
// @Contact 361554012@qq.com
package
routers
package
routers
import
(
"kefu_server/controllers"
...
...
@@ -51,6 +51,7 @@ func init() {
beego
.
NSRouter
(
"/workorder/create"
,
&
controllers
.
PublicController
{},
"post:CreateWorkOrder"
),
beego
.
NSRouter
(
"/workorder/reply"
,
&
controllers
.
PublicController
{},
"post:ReplyWorkOrder"
),
beego
.
NSRouter
(
"/workorders"
,
&
controllers
.
PublicController
{},
"get:GetWorkOrders"
),
beego
.
NSRouter
(
"/workorder/types"
,
&
controllers
.
PublicController
{},
"get:GetWorkOrderTypes"
),
beego
.
NSRouter
(
"/workorder/comments/:wid"
,
&
controllers
.
PublicController
{},
"get:GetWorkOrderComments"
),
beego
.
NSRouter
(
"/workorder/:wid"
,
&
controllers
.
PublicController
{},
"get:GetWorkOrder"
),
beego
.
NSRouter
(
"/workorder/:wid"
,
&
controllers
.
PublicController
{},
"delete:DeleteWorkOrder"
),
...
...
ui/kefu_client/plugins/help.js
View file @
e3a7f5bd
...
...
@@ -18,6 +18,10 @@ Helps.install = function (Vue, options) {
}
return
moment
(
parseInt
(
unix
+
'000'
)).
format
(
format
)
}
// 格式化日期(相对日期)
Vue
.
prototype
.
$formatDate
=
function
(
unix
,
format
=
"YYYY-MM-DD HH:mm:ss"
)
{
return
moment
(
parseInt
(
unix
+
'000'
)).
format
(
format
)
}
Vue
.
prototype
.
$robotNickname
=
function
(
id
)
{
var
nickname
var
robots
=
this
.
$store
.
getters
.
robots
...
...
ui/kefu_client/plugins/mimc.js
View file @
e3a7f5bd
...
...
@@ -36,20 +36,22 @@ MimcPlugin.install = function (Vue, options) {
localStorage
.
setItem
(
"user"
,
JSON
.
stringify
(
response
.
data
.
data
.
user
))
localStorage
.
setItem
(
"Token"
,
response
.
data
.
data
.
user
.
token
)
console
.
log
(
"MIMC初始化成功"
)
this
.
getRobot
()
if
(
callback
)
callback
(
response
.
data
.
data
.
user
)
this
.
getRobot
(()
=>
{
if
(
callback
)
callback
(
response
.
data
.
data
.
user
)
})
})
.
catch
((
error
)
=>
{
if
(
callback
)
callback
(
null
)
console
.
log
(
error
.
response
)
console
.
log
(
error
)
})
},
// 获取机器人
getRobot
(){
getRobot
(
callback
){
axios
.
get
(
'/public/robot/'
+
this
.
platform
)
.
then
(
response
=>
{
this
.
robot
=
response
.
data
.
data
})
if
(
callback
)
callback
()
})
.
catch
((
error
)
=>
{
console
.
log
(
"mimc初始化失败,请刷新重试"
,
error
)
})
...
...
ui/kefu_client/src/App.vue
View file @
e3a7f5bd
<
template
>
<div>
<router-view
/>
<div>
<div
class=
"mini-im-loading"
:class=
"
{'pc-mini-im-loading': !isMobile}"
v-if="isShowPageLoading"
>
<mt-spinner
type=
"triple-bounce"
color=
"#26a2ff"
></mt-spinner>
</div>
<router-view
/>
</div>
</
template
>
<
script
>
import
{
mapGetters
}
from
"vuex"
;
export
default
{
name
:
"app"
,
data
()
{
return
{
};
return
{};
},
computed
:
{
...
mapGetters
([
"isShowPageLoading"
,
"userAccount"
,
"isArtificial"
,
"isMobile"
,
"artificialAccount"
,
"robotAccount"
,
"platform"
,
"userLocal"
,
"uid"
,
"uid"
,
])
},
mounted
()
{
this
.
handelUrl
()
created
()
{
this
.
getLocal
();
setTimeout
(()
=>
{
this
.
handelUrl
()
this
.
runApp
()
},
500
);
// 判断是否被踢出对话
this
.
onCheckIsOutSession
();
},
methods
:
{
runApp
()
{
const
user
=
this
.
$mimcInstance
.
getLocalCacheUser
();
if
(
user
&&
this
.
userAccount
!=
null
&&
this
.
userAccount
!=
user
.
id
&&
this
.
userAccount
!=
0
)
{
localStorage
.
clear
();
}
this
.
$mimcInstance
.
init
(
{
type
:
0
,
// 默认0
address
:
this
.
userLocal
,
uid
:
this
.
uid
||
0
,
// 预留字段扩展自己平台业务
platform
:
this
.
platform
,
// 渠道(平台)
account_id
:
this
.
userAccount
||
0
// 用户ID
// 初始化完成这里返回一个user
},
user
=>
{
// 上报活动时间
this
.
upLastActivity
();
// 获取公司信息
this
.
$store
.
dispatch
(
"onGetCompanyInfo"
);
// 获取上传配置信息
this
.
$store
.
dispatch
(
"onGetUploadSecret"
);
// 获取工单类型
this
.
$store
.
dispatch
(
"onGetWorkorderTypes"
);
// 获取工单列表
this
.
$store
.
dispatch
(
"onGetWorkorders"
);
// 重试
if
(
!
user
)
{
setTimeout
(()
=>
this
.
runApp
(),
1000
);
return
;
}
// user
this
.
$store
.
commit
(
"updateState"
,
{
userAccount
:
user
.
id
,
userInfo
:
user
});
// robot
var
robot
=
this
.
$mimcInstance
.
robot
;
localStorage
.
setItem
(
"robot_"
+
robot
.
id
,
JSON
.
stringify
(
robot
));
this
.
$store
.
commit
(
"updateState"
,
{
robotAccount
:
robot
.
id
,
robotInfo
:
robot
});
// 登录mimc
this
.
$mimcInstance
.
login
();
// 发送一条握手消息给机器人
var
sentHandshake
=
()
=>
{
if
(
this
.
$mimcInstance
.
user
==
null
||
!
this
.
$mimcInstance
.
user
.
isLogin
())
{
setTimeout
(()
=>
sentHandshake
(),
200
);
return
}
if
(
!
this
.
artificialAccount
)
{
console
.
log
(
"握手消息"
);
this
.
$mimcInstance
.
sendMessage
(
"handshake"
,
this
.
robotAccount
,
""
);
}
}
sentHandshake
()
}
);
},
// Handelurl
handelUrl
()
{
// url query 介绍
...
...
@@ -30,8 +133,15 @@ export default {
// u == userAccount 会话用户账号
// uid == userId 业务平台的ID
// c = 1 清除本地缓存
var
isShowHeader
,
isMobile
,
userAccount
,
uid
,
isArtificial
,
artificialAccount
,
robotAccount
,
platform
var
query
=
this
.
queryToJson
(
location
.
search
);
var
isShowHeader
,
isMobile
,
userAccount
,
uid
,
isArtificial
,
artificialAccount
,
robotAccount
,
platform
;
var
query
=
this
.
$route
.
query
;
if
(
query
&&
query
.
c
)
localStorage
.
clear
();
// 获取本地缓存
var
urlQuery
=
this
.
queryToJson
(
localStorage
.
getItem
(
"urlQuery"
));
...
...
@@ -48,19 +158,28 @@ export default {
if
(
query
.
p
)
platform
=
parseInt
(
query
.
p
);
if
(
query
.
uid
)
uid
=
parseInt
(
query
.
uid
);
if
(
query
.
r
==
"0"
)
{
isArtificial
=
true
artificialAccount
=
parseInt
(
query
.
a
)
isArtificial
=
true
;
artificialAccount
=
parseInt
(
query
.
a
);
}
else
{
robotAccount
=
parseInt
(
query
.
a
)
robotAccount
=
parseInt
(
query
.
a
);
}
}
var
isArtificialString
=
localStorage
.
getItem
(
"isArtificial"
);
var
artificialAccountString
=
localStorage
.
getItem
(
"artificialAccount"
);
if
(
isArtificialString
==
"true"
)
{
isArtificial
=
true
artificialAccount
=
parseInt
(
artificialAccountString
)
isArtificial
=
true
;
artificialAccount
=
parseInt
(
artificialAccountString
);
}
this
.
$store
.
commit
(
"updateState"
,
{
isShowHeader
,
isMobile
,
userAccount
,
uid
,
isArtificial
,
artificialAccount
,
robotAccount
,
platform
})
this
.
$store
.
commit
(
"updateState"
,
{
isShowHeader
,
isMobile
,
userAccount
,
uid
,
isArtificial
,
artificialAccount
,
robotAccount
,
platform
});
},
// query 转json
queryToJson
(
str
)
{
...
...
@@ -74,7 +193,33 @@ export default {
}
return
mapData
;
},
// 根据IP获取用户地理位置
getLocal
()
{
this
.
$store
.
dispatch
(
"onGetLocal"
,
this
.
$store
.
state
.
AmapAPPKey
);
},
// 上报最后活动时间
upLastActivity
()
{
this
.
onCheckIsOutSession
();
const
user
=
this
.
$mimcInstance
.
getLocalCacheUser
();
if
(
user
)
this
.
$store
.
dispatch
(
"onUpdateLastActivity"
);
if
(
this
.
isArtificial
)
{
localStorage
.
setItem
(
"artificialTime"
,
Date
.
now
());
}
setTimeout
(()
=>
this
.
upLastActivity
(),
1000
*
60
);
},
// 判断是否被踢出对话
onCheckIsOutSession
()
{
var
artificialTime
=
localStorage
.
getItem
(
"artificialTime"
);
if
(
artificialTime
)
{
artificialTime
=
parseInt
(
artificialTime
);
if
(
Date
.
now
()
>
artificialTime
+
60
*
1000
*
10
)
{
this
.
$store
.
commit
(
"updateState"
,
{
isArtificial
:
false
,
artificialAccount
:
null
});
}
}
},
}
};
</
script
>
...
...
@@ -114,5 +259,26 @@ body {
font-size
:
23px
!important
;
}
.mini-im-loading
{
display
:
flex
;
width
:
100%
;
position
:
fixed
;
height
:
100vh
;
top
:
0
;
left
:
0
;
z-index
:
9
;
right
:
0
;
background-color
:
#fff
!important
;
margin
:
auto
;
align-items
:
center
;
justify-content
:
center
;
&.pc-mini-im-loading
{
width
:
360px
!important
;
height
:
360px
!important
;
top
:
-48px
;
bottom
:
0
;
margin
:
auto
!important
;
}
}
</
style
>
ui/kefu_client/src/assets/workorder.png
View file @
e3a7f5bd
391 Bytes
|
W:
|
H:
1.1 KB
|
W:
|
H:
2-up
Swipe
Onion skin
ui/kefu_client/src/router.js
View file @
e3a7f5bd
...
...
@@ -25,7 +25,7 @@ const router = new Router({
component
:
()
=>
import
(
'./views/workorder_create.vue'
)
},
{
path
:
'/workorder/detail'
,
path
:
'/workorder/detail
/:id
'
,
name
:
'workorder_detail'
,
component
:
()
=>
import
(
'./views/workorder_detail.vue'
)
},
...
...
ui/kefu_client/src/store/actions.js
View file @
e3a7f5bd
...
...
@@ -14,13 +14,15 @@ export default {
.
then
(
response
=>
{
let
newMessage
=
[];
let
messages
=
response
.
data
.
data
.
list
||
[];
if
(
messages
.
length
<
pageSize
)
{
if
(
messages
.
length
<
pageSize
||
messages
.
length
==
0
)
{
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
);
}
else
{
newMessage
=
params
.
oldMsg
}
context
.
commit
(
'updateState'
,
{
messages
:
newMessage
})
if
(
params
.
callback
)
params
.
callback
()
...
...
@@ -71,5 +73,17 @@ export default {
axios
.
get
(
"/public/secret"
).
then
(
response
=>
{
context
.
commit
(
'updateState'
,
{
uploadToken
:
response
.
data
.
data
})
});
},
// 获取工单类型
onGetWorkorderTypes
(
context
){
axios
.
get
(
"/public/workorder/types"
).
then
(
response
=>
{
context
.
commit
(
'updateState'
,
{
workorderTypes
:
response
.
data
.
data
})
});
},
// 获取工单列表
onGetWorkorders
(
context
){
axios
.
get
(
"/public/workorders"
).
then
(
response
=>
{
context
.
commit
(
'updateState'
,
{
workorders
:
response
.
data
.
data
})
});
}
}
\ No newline at end of file
ui/kefu_client/src/store/getters.js
View file @
e3a7f5bd
...
...
@@ -62,5 +62,14 @@ export default {
let
limit
=
window
.
screen
.
height
==
window
.
screen
.
availHeight
?
1.8
:
1.65
;
if
(
rate
>
limit
)
yes
=
true
;
return
yes
;
},
isShowPageLoading
(
state
){
return
state
.
isShowPageLoading
},
workorders
(
state
){
return
state
.
workorders
},
workorderTypes
(
state
){
return
state
.
workorderTypes
}
}
\ No newline at end of file
ui/kefu_client/src/store/state.js
View file @
e3a7f5bd
export
default
{
platform
:
5
,
// 平台(渠道)
isShowPageLoading
:
false
,
// page loading
isShowHeader
:
true
,
// 是否显示header
isMobile
:
true
,
// 是否是移动端
isArtificial
:
false
,
// 是否是人工服务
...
...
@@ -16,4 +17,9 @@ export default {
userInfo
:
{},
// 用户信息
companyInfo
:
null
,
// 公司信息
uploadToken
:
null
,
// 上传token
// workorder
workorders
:
[],
// 工单列表
workorderTypes
:
[],
// 工单类型列表
}
\ No newline at end of file
ui/kefu_client/src/views/kefu.vue
View file @
e3a7f5bd
This diff is collapsed.
Click to expand it.
ui/kefu_client/src/views/workorder.vue
View file @
e3a7f5bd
<
template
>
<div
class=
"container"
>
<mt-header
v-if=
"isShowHeader"
fixed
title=
"工单"
>
<mt-header
v-if=
"isShowHeader"
fixed
title=
"
我的
工单"
>
<div
slot=
"left"
>
<mt-button
@
click=
"$router.go(-1)"
icon=
"back"
></mt-button>
</div>
...
...
@@ -9,6 +9,26 @@
<span>
创建工单
</span>
</mt-button>
</mt-header>
<div
class=
"list"
:class=
"
{'hide-header': !isShowHeader}">
<div
class=
"no-data"
v-if=
"workorders.lenght
<
=
0
"
>
<img
src=
"../assets/workorder.png"
alt=
""
>
<div>
您还没有发布过工单~
</div>
</div>
<ul
v-else
>
<template
v-for=
"(item,index) in workorders"
>
<li
:key=
"index"
@
click=
"$router.push('/workorder/detail/'+item.id)"
>
<div
class=
"title"
>
{{
item
.
title
}}
</div>
<div>
<span
class=
"type"
>
{{
getTypeName
(
item
.
tid
)
}}
</span>
<span
class=
"date"
>
{{
$formatDate
(
item
.
create_at
)
}}
</span>
</div>
<i
v-if=
"item.status == 1"
style=
"color:#FF9800;"
>
客服已回复
</i>
<i
v-if=
"item.status == 3"
style=
"color:#ccc"
>
工单已结束
</i>
<i
v-if=
"item.status == 0 || item.status == 2"
style=
"color:green"
>
待回复
</i>
</li>
</
template
>
</ul>
</div>
</div>
</template>
...
...
@@ -20,18 +40,89 @@ export default {
data
()
{
return
{};
},
created
()
{
document
.
title
=
"我的工单"
},
computed
:
{
...
mapGetters
([
'isShowHeader'
'isShowHeader'
,
'workorders'
,
'workorderTypes'
,
])
},
mounted
()
{},
mounted
()
{
// 获取工单类型
this
.
$store
.
dispatch
(
"onGetWorkorderTypes"
);
// 获取工单列表
this
.
$store
.
dispatch
(
"onGetWorkorders"
);
},
methods
:
{
getTypeName
(
tid
){
try
{
return
this
.
workorderTypes
.
filter
((
i
)
=>
i
.
id
==
tid
)[
0
].
title
}
catch
(
e
){
console
.
log
(
e
)
return
""
}
}
}
};
</
script
>
<
style
lang=
"stylus"
scoped
>
.no-data
{
text-align
center
padding-top
50px
img{
width
50px
height
50px
}
div
{
color
#666
font-size
12px
}
}
.list
{
padding-top
50px
&.hide-header{
padding-top
0
}
li
{
padding
10px
20px
background
url('../assets/workorder.png')
10px
center
no-repeat
background-size
25px
padding-left
40px
padding-right
70px
border-bottom
1px
solid
#ddd
position
relative
height
40px
.title{
font-size
14px
color
#333
text-overflow
:
ellipsis
;
overflow
:
hidden
;
white-space
:
nowrap
;
}
.type
{
font-size
12px
color
#666
}
.date
{
margin-left
10px
font-size
12px
color
#999
}
i
{
font-style
normal
font-size
11px
position
absolute
right
10px
top
0
height
:
20px
;
bottom
0
margin
auto
0
}
}
}
</
style
>
ui/kefu_client/src/views/workorder_detail.vue
View file @
e3a7f5bd
<
template
>
<div
class=
"container"
>
workorder_detail
<mt-header
v-if=
"isShowHeader"
fixed
:title=
"workorder.title || '工单详情'"
>
<div
slot=
"left"
>
<mt-button
@
click=
"$router.go(-1)"
icon=
"back"
></mt-button>
</div>
<mt-button
slot=
"right"
>
<span>
删除
</span>
</mt-button>
</mt-header>
</div>
</
template
>
<
script
>
import
{
mapGetters
}
from
'vuex'
import
axios
from
"axios"
;
export
default
{
name
:
"workorder_detail"
,
components
:
{},
data
()
{
return
{};
return
{
workorder
:
{},
};
},
mounted
()
{},
methods
:
{}
computed
:
{
...
mapGetters
([
'isShowHeader'
,
'workorders'
,
'workorderTypes'
,
])
},
created
()
{
document
.
title
=
"工单详情"
const
id
=
this
.
$route
.
params
.
id
this
.
getWorkOrder
(
id
)
},
methods
:
{
getWorkOrder
(
id
){
axios
.
get
(
"/public/workorder/"
+
id
).
then
(
response
=>
{
this
.
workorder
=
response
.
data
.
data
console
.
log
(
this
.
workorder
)
}).
catch
(
error
=>
{
console
.
log
(
error
)
});
}
}
};
</
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