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
9541c36a
authored
Mar 23, 2020
by
chenxianqi
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
add create workorder
parent
1142582d
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
582 additions
and
223 deletions
ui/kefu_client/src/App.vue
ui/kefu_client/src/assets/arrow.png
ui/kefu_client/src/views/workorder_create.vue
ui/kefu_client/src/views/workorder_detail.vue
ui/kefu_client/src/App.vue
View file @
9541c36a
...
...
@@ -281,4 +281,7 @@ body {
margin
:
auto
!important
;
}
}
.workorder-create-picker
.picker-item
{
font-size
15px
}
</
style
>
ui/kefu_client/src/assets/arrow.png
0 → 100644
View file @
9541c36a
1.32 KB
ui/kefu_client/src/views/workorder_create.vue
View file @
9541c36a
<
template
>
<div
class=
"container"
>
workorder_create
<mt-header
v-if=
"isShowHeader"
fixed
title=
"创建工单"
>
<div
slot=
"left"
>
<mt-button
@
click=
"$router.go(-1)"
icon=
"back"
></mt-button>
</div>
</mt-header>
<div
class=
"content"
:class=
"
{'hide-header': !isShowHeader}">
<div
class=
"field-line arrow-right"
@
click=
"isShowTypesPicker = true"
>
<span>
类型:
</span>
<span>
{{
selectTyped
||
'选择工单分类'
}}
</span>
</div>
<div
class=
"field-line algin-left"
>
<span>
标题:
</span>
<input
type=
"text"
v-model=
"request.title"
placeholder=
"请输入工单标题~"
>
</div>
<div
class=
"field-line algin-left"
>
<span>
手机:
</span>
<input
type=
"number"
v-model=
"request.phone"
placeholder=
"请输入您的手机~"
>
</div>
<div
class=
"tip"
>
必填,预留手机号方便客服联系到您~
</div>
<div
class=
"field-line algin-left"
>
<span>
邮箱:
</span>
<input
type=
"email"
v-model=
"request.email"
placeholder=
"请输入您的电子邮箱~"
>
</div>
<div
class=
"tip"
>
非必填,预留邮箱后若工单回复后会通过邮箱通知您~
</div>
<div
class=
"field-line textarea"
>
<span>
内容:
</span>
<textarea
v-model=
"request.content"
placeholder=
"请输入您的工单内容~"
></textarea>
</div>
<div
class=
"field-line arrow-right file"
>
<span>
附件:
</span>
<span>
{{
file
||
'上传附件'
}}
</span>
<input
type=
"file"
/>
</div>
<span
class=
"sub-btn"
@
click=
"submit()"
>
提交
</span>
</div>
<!-- types-sheet -->
<div
class=
"types-sheet"
v-if=
"isShowTypesPicker"
>
<!--
<div
class=
"mask"
@
click=
"isShowTypesPicker = false"
></div>
-->
<div
class=
"picker-box"
>
<div
class=
"title"
>
<span>
选择工单类型
</span>
<span
class=
"sub-btn"
@
click=
"isShowTypesPicker = false"
>
确定
</span>
</div>
<mt-picker
:slots=
"types"
@
change=
"onValuesChange"
></mt-picker>
</div>
</div>
</div>
</
template
>
<
script
>
import
{
mapGetters
}
from
"vuex"
;
import
{
Toast
}
from
"mint-ui"
;
import
axios
from
"axios"
;
export
default
{
name
:
"workorder_create"
,
components
:
{},
data
()
{
return
{};
return
{
isSubmit
:
false
,
request
:
{
"tid"
:
0
,
"title"
:
""
,
"content"
:
""
,
"phone"
:
""
,
"email"
:
""
},
selectTyped
:
""
,
file
:
""
,
isShowTypesPicker
:
false
};
},
computed
:
{
...
mapGetters
([
"isShowHeader"
,
"workorders"
,
"userInfo"
,
"workorderTypes"
,
"uploadToken"
,
"workorderTypes"
]),
types
()
{
var
values
=
[];
var
slot
=
[
{
flex
:
1
,
values
:
[],
className
:
"workorder-create-picker"
,
textAlign
:
"center"
}
];
for
(
var
i
=
0
;
i
<
this
.
workorderTypes
.
length
;
i
++
)
{
values
.
push
(
this
.
workorderTypes
[
i
].
title
);
}
slot
[
0
].
values
=
values
;
return
slot
;
}
},
mounted
()
{
},
methods
:
{
onValuesChange
(
_
,
values
)
{
this
.
selectTyped
=
values
[
0
]
for
(
var
i
=
0
;
i
<
this
.
workorderTypes
.
length
;
i
++
){
if
(
values
[
0
]
==
this
.
workorderTypes
[
i
].
title
){
this
.
request
.
tid
=
this
.
workorderTypes
[
i
].
id
break
}
}
console
.
log
(
_
)
},
mounted
()
{},
methods
:
{}
submit
(){
if
(
this
.
request
.
tid
==
0
){
Toast
({
message
:
"请选择工单类型!"
});
return
}
if
(
this
.
request
.
title
.
trim
()
==
""
){
Toast
({
message
:
"工单标题不能为空!"
});
return
}
if
(
this
.
request
.
content
.
trim
()
==
""
){
Toast
({
message
:
"工单内容不能为空!"
});
return
}
if
(
this
.
isSubmit
)
return
this
.
isSubmit
=
true
axios
.
post
(
"/public/workorder/create"
,
this
.
request
)
.
then
(
response
=>
{
this
.
isSubmit
=
false
Toast
({
message
:
"工单创建成功~"
});
setTimeout
(()
=>
this
.
$router
.
replace
(
"/workorder/detail/"
+
response
.
data
.
data
),
500
)
})
.
catch
(
error
=>
{
this
.
isSubmit
=
false
Toast
({
message
:
error
.
response
.
data
.
message
});
console
.
log
(
error
);
});
}
}
};
</
script
>
<
style
lang=
"stylus"
scoped
>
.content
{
padding
50px
10px
.field-line{
display
flex
justify-content
space-between
box-sizing
border-box
height
45px
border-bottom
1px
solid
#ddd
align-content
center
align-items
center
font-size
14px
color
#333
span
:
first-child
{
width
35px
}
input
{
flex-grow
1
padding-left
10px
height
100%
background
none
border
0
color
#333
font-size
14px
border-radius
0
}
&
.algin-left
{
align-content
left
align-items
left
}
&
.arrow-right
{
background
url(./../assets/arrow.png)
right
center
no-repeat
background-size
18px
padding-right
25px
}
&
.file
{
position
relative
overflow
hidden
margin-top
20px
border-top
1px
solid
#ddd
input{
font-size
100px
opacity
0
position
absolute
top
0
right
0
}
}
&
.textarea
{
align-items
start
align-content
start
border-bottom
0
padding-top
10px
height
100px
textarea{
flex-grow
1
border
0
height
100%
resize
none
color
#333
font-size
14px
padding
3px
10px
background-color
rgba(0,
0,
0,
0.03);
border-radius
3px
}
}
}
.tip
{
font-size
11px
color
#ff9800
}
&
.hide-header
{
padding-top
:
0
;
}
.sub-btn
{
display
:
block
;
width
:
100%
;
height
:
45px
;
color
:
#fff
;
margin-top
30px
line-height
:
45px
;
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
;
}
}
}
.types-sheet
{
width
100vw;
height
100vh
position
fixed
top
0
left
0
right
0
bottom
0
margin
auto
background-color
rgba(0,0,0,.5)
//
.mask{
//
width
100vw;
//
height
100vh
//
background-color
rgba(0,0,0,.5)
//
}
.picker-box
{
height
250px
width
100vw
position
absolute
bottom
0
left
0
right
0
margin
0
auto
background-color
#fff
}
.title
{
height
35px
border-bottom
1px
solid
#f3f3f3
display
flex
justify-content
space-between
padding
0
10px
box-sizing
border-box
align-content
center
align-items
center
span{
font-size
14px
color
#333
}
.sub-btn
{
display
:
block
;
width
:
55px
;
height
:
30px
;
color
:
#26a2ff
line-height
:
30px
;
text-align
:
right
;
font-size
:
14px
;
font-weight
900
&:active
{
opacity
:
0.8
;
}
}
}
}
</
style
>
ui/kefu_client/src/views/workorder_detail.vue
View file @
9541c36a
...
...
@@ -7,6 +7,9 @@
<mt-button
@
click=
"close()"
v-if=
"workorder.status != 3"
slot=
"right"
>
<span>
关闭工单
</span>
</mt-button>
<mt-button
@
click=
"del()"
v-else
slot=
"right"
>
<span>
删除
</span>
</mt-button>
</mt-header>
<div
class=
"content"
:class=
"
{'hide-header': !isShowHeader}">
<div
class=
"head"
>
...
...
@@ -45,8 +48,12 @@
<template
v-else
v-for=
"(item,index) in comments"
>
<div
:key=
"index"
class=
"item"
>
<div
class=
"avatar"
>
<img
v-if=
"item.aid == '0'"
:src=
"userInfo.avatar || 'http://qiniu.cmp520.com/avatar_degault_3.png'"
alt=
""
>
<img
v-else
:src=
"item.avatar || 'http://qiniu.cmp520.com/avatar_degault_3.png'"
alt=
""
>
<img
v-if=
"item.aid == '0'"
:src=
"userInfo.avatar || 'http://qiniu.cmp520.com/avatar_degault_3.png'"
alt
/>
<img
v-else
:src=
"item.avatar || 'http://qiniu.cmp520.com/avatar_degault_3.png'"
alt
/>
</div>
<div
class=
"right"
>
<div
class=
"nickname"
v-if=
"item.aid == '0'"
>
我
</div>
...
...
@@ -56,17 +63,15 @@
</div>
</div>
</
template
>
<div
class=
"workorder-close"
v-if=
"workorder.status == 3"
>
工单已结束~
</div>
<div
class=
"workorder-close"
v-if=
"workorder.status == 3"
>
工单已结束~
</div>
</div>
<div
class=
"file-view"
v-if=
"request.file != '' || isShowUploadLoading"
>
<span
v-if=
"isShowUploadLoading"
>
<img
src=
"./../assets/loading.gif"
alt
=
""
>
<img
src=
"./../assets/loading.gif"
alt
/
>
<i>
上传中~
</i>
</span>
<span
v-else
>
<img
src=
"./../assets/fujian1.png"
alt
=
""
>
<img
src=
"./../assets/fujian1.png"
alt
/
>
<i>
你已成功添加附件,重新上传可替换~
</i>
</span>
</div>
...
...
@@ -81,8 +86,8 @@
</div>
</template>
<
script
>
import
{
mapGetters
}
from
'vuex'
import
{
Toast
,
MessageBox
}
from
'mint-ui'
;
import
{
mapGetters
}
from
"vuex"
;
import
{
Toast
,
MessageBox
}
from
"mint-ui"
;
import
axios
from
"axios"
;
export
default
{
name
:
"workorder_detail"
,
...
...
@@ -92,127 +97,167 @@ export default {
isShowUploadLoading
:
false
,
isSubmit
:
false
,
workorder
:
{},
comments
:[],
comments
:
[],
fileType
:
""
,
request
:{
request
:
{
file
:
""
,
content
:
""
,
content
:
""
}
};
},
computed
:
{
...
mapGetters
([
'isShowHeader'
,
'workorders'
,
'userInfo'
,
'workorderTypes'
,
"isShowHeader"
,
"workorders"
,
"userInfo"
,
"workorderTypes"
,
"uploadToken"
])
},
created
()
{
document
.
title
=
"工单详细"
const
id
=
this
.
$route
.
params
.
id
this
.
$store
.
commit
(
"updateState"
,
{
isShowPageLoading
:
true
});
axios
.
all
([
this
.
getWorkOrder
(
id
),
this
.
getComments
(
id
)])
.
then
(
axios
.
spread
(()
=>
{
this
.
$store
.
commit
(
"updateState"
,
{
isShowPageLoading
:
false
});
}));
document
.
title
=
"工单详细"
;
const
id
=
this
.
$route
.
params
.
id
;
this
.
$store
.
commit
(
"updateState"
,
{
isShowPageLoading
:
true
});
axios
.
all
([
this
.
getWorkOrder
(
id
),
this
.
getComments
(
id
)]).
then
(
axios
.
spread
(()
=>
{
this
.
$store
.
commit
(
"updateState"
,
{
isShowPageLoading
:
false
});
})
);
},
methods
:
{
commentView
(
comment
){
var
res
=
comment
.
match
(
/
\[
file=
(
.*
)\]
/
)
if
(
res
==
null
)
return
comment
var
fileType
=
res
[
1
].
substr
(
res
[
1
].
lastIndexOf
(
'.'
)
+
1
)
if
(
"jpg,jpeg,png,JPG,JPEG,PNG"
.
indexOf
(
fileType
)
!=
-
1
){
comment
=
comment
.
replace
(
res
[
0
],
"
<
br
><
img
style
=
'max-width:60%'
preview
=
'1'
src
=
'"+res[1]+"'
/>
")
commentView
(
comment
)
{
var
res
=
comment
.
match
(
/
\[
file=
(
.*
)\]
/
);
if
(
res
==
null
)
return
comment
;
var
fileType
=
res
[
1
].
substr
(
res
[
1
].
lastIndexOf
(
"."
)
+
1
);
if
(
"jpg,jpeg,png,JPG,JPEG,PNG"
.
indexOf
(
fileType
)
!=
-
1
)
{
comment
=
comment
.
replace
(
res
[
0
],
"
<
br
><
img
style
=
'max-width:60%'
preview
=
'1'
src
=
'" + res[1] + "'
/>
"
);
this.$previewRefresh();
}
return comment
return comment
;
},
getWorkOrder(id){
return axios.get("
/
public
/
workorder
/
"+id).then(response => {
this.workorder = response.data.data
}).catch(error => {
console.log(error)
getWorkOrder(id) {
return axios
.get("
/
public
/
workorder
/
" + id)
.then(response => {
this.workorder = response.data.data;
})
.catch(error => {
console.log(error);
});
},
getComments(id){
return axios.get("
/
public
/
workorder
/
comments
/
"+id).then(response => {
if(response.data.data == null) return;
this.comments = response.data.data
}).catch(error => {
console.log(error)
getComments(id) {
return axios
.get("
/
public
/
workorder
/
comments
/
" + id)
.then(response => {
if (response.data.data == null) return;
this.comments = response.data.data;
})
.catch(error => {
console.log(error);
});
},
reply(){
const content = this.request.content + this.request.file
if
(content.trim() == '')
{
reply()
{
const content = this.request.content + this.request.file
;
if
(content.trim() == "")
{
Toast({
message: "
请输入内容
~
"
})
return
}
if(this.isSubmit) return
this.isSubmit = true
const wid = this.workorder.id
axios.post("
/
public
/
workorder
/
reply
", {wid, content}).then(response => {
this.getComments(wid)
});
return;
}
if (this.isSubmit) return;
this.isSubmit = true;
const wid = this.workorder.id;
axios
.post("
/
public
/
workorder
/
reply
", { wid, content })
.then(response => {
this.isSubmit = false
console.log(response);
this.getComments(wid);
this.request = {
file: "",
content: "",
}
}).catch(error => {
content: ""
};
})
.catch(error => {
this.isSubmit = false
console.log(error);
Toast({
message: "
提交失败
~
"
})
});
});
},
inputBlur(){
setTimeout(() => {
document.body.scrollTo = 0;
window.scrollTo(0,
0);
},
100);
inputBlur()
{
setTimeout(() => {
document.body.scrollTo = 0;
window.scrollTo(0,
0);
},
100);
},
uploadFile(e){
uploadFile(e)
{
var fileDom = e.target;
var file = fileDom.files[0];
this.isShowUploadLoading = true
const self = this
this.isShowUploadLoading = true
;
const self = this
;
this.$uploadFile({
file,
mode: this.uploadToken.mode,
// 七牛才会执行
percent(res
) {},
percent(
) {},
success(src) {
self.request.file = '[file=' + self.uploadToken.host + '/' + src + ']'
self.isShowUploadLoading = false
self.request.file =
"
[
file
=
" + self.uploadToken.host + "
/
" + src + "
]
";
self.isShowUploadLoading = false;
},
fail(e) {
self.isShowUploadLoading = false
if(e.response && e.response.data)
{
self.isShowUploadLoading = false;
if (e.response && e.response.data)
{
Toast({
message: e.response.data.message
})
return
});
return;
}
}
});
},
close(){
var wid = this.workorder.id
MessageBox.confirm('您确定关闭该工单吗?').then(action => {
axios.put("
/
public
/
workorder
/
close
/
"+wid).then(response => {
close() {
var wid = this.workorder.id;
MessageBox.confirm("
您确定关闭该工单吗
?
").then(() => {
axios
.put("
/
public
/
workorder
/
close
/
" + wid)
.then(response => {
console.log(response);
Toast({
message: "
工单已关闭
~
"
});
this.getWorkOrder(wid);
})
this.getWorkOrder(wid)
}).catch(error => {
.catch(error => {
Toast({
message: "
工单关闭失败
~
"
});
console.log(error);
});
});
},
del() {
var wid = this.workorder.id;
MessageBox.confirm("
您确定删除该工单吗
?
").then(() => {
axios
.delete("
/
public
/
workorder
/
" + wid)
.then(response => {
console.log(response);
Toast({
message: "
工单已删除
~
"
});
setTimeout(() => this.$router.go(-1));
})
console
.
log
(
error
)
.catch(error => {
Toast({
message: "
工单关闭失败
~
"
});
console
.
log
(
error
);
});
});
}
...
...
@@ -220,154 +265,181 @@ export default {
};
</
script
>
<
style
lang=
"stylus"
scoped
>
.container
{
height
100vh
overflow
hidden
overflow-y
auto
}
.content
{
padding-top
50px
.container
{
height
:
100vh
;
overflow
:
hidden
;
overflow-y
:
auto
;
}
.content
{
padding-top
:
50px
;
padding-bottom
:
90px
;
.no-data{
color
#666
font-size
14px
}
.workorder-close
{
text-align
center
color
#666
font-size
14px
padding
10px
}
&
.hide-header
{
padding-top
0
}
.head
{
margin
0
10px
padding
10px
0
border-bottom
1px
solid
rgba(158,
158,
158,
0.13);
.con{
font-size
15px
color
#333
display
flex
margin-bottom
8px
span{
flex-flow
1
}
span
:first-child
{
flex-flow
0
flex-shrink
0
width
45px
}
i
{
font-style
normal
.no-data
{
color
:
#666
;
font-size
:
14px
;
}
.workorder-close
{
text-align
:
center
;
color
:
#666
;
font-size
:
14px
;
padding
:
10px
;
}
&
.hide-header
{
padding-top
:
0
;
}
.head
{
margin
:
0
10px
;
padding
:
10px
0
;
border-bottom
:
1px
solid
rgba
(
158
,
158
,
158
,
0.13
);
.con
{
font-size
:
15px
;
color
:
#333
;
display
:
flex
;
margin-bottom
:
8px
;
span
{
flex-flow
:
1
;
}
span
:first-child
{
flex-flow
:
0
;
flex-shrink
:
0
;
width
:
45px
;
}
i
{
font-style
:
normal
;
}
}
}
.comments
{
padding
:
10px
;
.item
{
display
:
flex
;
.avatar
{
padding-top
:
10px
;
img
{
width
:
30px
;
height
:
30px
;
border-radius
:
100px
;
display
:
block
;
}
border-bottom
:
1px
solid
rgba
(
158
,
158
,
158
,
0
.13
);
}
.right
{
padding
:
10px
5px
;
flex-grow
:
1
;
border-bottom
:
1px
solid
rgba
(
158
,
158
,
158
,
0.13
);
.nickname
{
font-size
:
15px
;
color
:
#333
;
}
.detail
{
font-size
:
15px
;
color
:
#333
;
margin-top
:
5px
;
}
.date
{
color
:
#999
;
font-size
:
14px
;
margin-top
:
5px
;
}
}
&
:last-child
{
.right,
.avatar
{
border-bottom
:
0
;
}
}
.comments
{
padding
10px
.item{
display
flex
.avatar{
padding-top
10px
img{
width
35px
height
35px
border-radius
100px
display
block
}
border-bottom
1px
solid
rgba
(
158
,
158
,
158
,
0
.13
);
}
.right
{
padding
10px
5px
flex-grow
1
border-bottom
1px
solid
rgba(158,
158,
158,
0.13);
.nickname{
font-size
15px
color
#333
}
.detail
{
font-size
15px
color
#333
margin-top
5px
}
.date
{
color
#999
font-size
14px
margin-top
5px
}
}
&
:last-child
{
.right,.avatar{
border-bottom
0
}
}
}
}
.file-view
{
position
fixed
bottom
80px
left
0
right
0
padding
5px
10px
margin
0
auto
font-size
13px
color
#8bc34a;
}
}
.file-view
{
position
:
fixed
;
bottom
:
80px
;
left
:
0
;
right
:
0
;
padding
:
5px
10px
;
margin
:
0
auto
;
font-size
:
13px
;
color
:
#8bc34a
;
span
{
display
flex
align-content
center
align-items
center
img{
width
20px
height
20px
}
i
{
font-style
normal
margin-left
5px
}
}
}
.input-form
{
position
fixed
bottom
0
left
0
right
0
margin
0
auto
width
100%
height
80px
background-color
#fff
border-top
1px
solid
rgba(158,
158,
158,
0.13);
display
flex
justify-content
space-between
padding
0
10px
box-sizing
border-box
align-content
center
align-items
center
textarea{
height
45px
flex-grow
1
border-radius
0
border
0
color
#333
font-size
14px
resize
none
}
.icon-btn
{
background
url(./../assets/upload.png)
center
center
no-repeat
background-size
30px
display
:
flex
;
align-content
:
center
;
align-items
:
center
;
img
{
width
:
20px
;
height
:
20px
;
}
i
{
font-style
:
normal
;
margin-left
:
5px
;
}
}
}
.input-form
{
position
:
fixed
;
bottom
:
0
;
left
:
0
;
right
:
0
;
margin
:
0
auto
;
width
:
100%
;
height
:
80px
;
background-color
:
#fff
;
border-top
:
1px
solid
rgba
(
158
,
158
,
158
,
0.13
);
display
:
flex
;
justify-content
:
space-between
;
padding
:
0
10px
;
box-sizing
:
border-box
;
align-content
:
center
;
align-items
:
center
;
textarea
{
height
:
45px
;
flex-grow
:
1
;
border-radius
:
0
;
border
:
0
;
color
:
#333
;
font-size
:
14px
;
resize
:
none
;
}
.icon-btn
{
background
:
url('./../assets/upload.png')
center
center
no-repeat
;
background-size
:
30px
;
width
:
55px
;
height
55px
overflow
hidden
input{
display
block
width
100%
height
100%
font-size
100px
opacity
0
height
:
55px
;
overflow
:
hidden
;
input
{
display
:
block
;
width
:
100%
;
height
:
100%
;
font-size
:
100px
;
opacity
:
0
;
}
}
.sub-btn
{
display
block
display
:
block
;
width
:
55px
;
height
:
30px
;
color
:
#fff
;
...
...
@@ -384,6 +456,6 @@ export default {
}
}
}
}
}
</
style
>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment