Commit 9541c36a by chenxianqi

add create workorder

parent 1142582d
...@@ -281,4 +281,7 @@ body { ...@@ -281,4 +281,7 @@ body {
margin: auto !important; margin: auto !important;
} }
} }
.workorder-create-picker .picker-item{
font-size 15px
}
</style> </style>
<template> <template>
<div class="container"> <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> </div>
</template> </template>
<script> <script>
import { mapGetters } from "vuex";
import { Toast } from "mint-ui";
import axios from "axios";
export default { export default {
name: "workorder_create", name: "workorder_create",
components: {}, components: {},
data() { 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() {}, submit(){
methods: {} 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> </script>
<style lang="stylus" scoped> <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> </style>
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
<mt-button @click="close()" v-if="workorder.status != 3" slot="right"> <mt-button @click="close()" v-if="workorder.status != 3" slot="right">
<span>关闭工单</span> <span>关闭工单</span>
</mt-button> </mt-button>
<mt-button @click="del()" v-else slot="right">
<span>删除</span>
</mt-button>
</mt-header> </mt-header>
<div class="content" :class="{'hide-header': !isShowHeader}"> <div class="content" :class="{'hide-header': !isShowHeader}">
<div class="head"> <div class="head">
...@@ -45,8 +48,12 @@ ...@@ -45,8 +48,12 @@
<template v-else v-for="(item,index) in comments"> <template v-else v-for="(item,index) in comments">
<div :key="index" class="item"> <div :key="index" class="item">
<div class="avatar"> <div class="avatar">
<img v-if="item.aid == '0'" :src="userInfo.avatar || 'http://qiniu.cmp520.com/avatar_degault_3.png'" alt=""> <img
<img v-else :src="item.avatar || 'http://qiniu.cmp520.com/avatar_degault_3.png'" alt=""> 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>
<div class="right"> <div class="right">
<div class="nickname" v-if="item.aid == '0'"></div> <div class="nickname" v-if="item.aid == '0'"></div>
...@@ -56,17 +63,15 @@ ...@@ -56,17 +63,15 @@
</div> </div>
</div> </div>
</template> </template>
<div class="workorder-close" v-if="workorder.status == 3"> <div class="workorder-close" v-if="workorder.status == 3">工单已结束~</div>
工单已结束~
</div>
</div> </div>
<div class="file-view" v-if="request.file != '' || isShowUploadLoading"> <div class="file-view" v-if="request.file != '' || isShowUploadLoading">
<span v-if="isShowUploadLoading"> <span v-if="isShowUploadLoading">
<img src="./../assets/loading.gif" alt=""> <img src="./../assets/loading.gif" alt />
<i>上传中~</i> <i>上传中~</i>
</span> </span>
<span v-else> <span v-else>
<img src="./../assets/fujian1.png" alt=""> <img src="./../assets/fujian1.png" alt />
<i>你已成功添加附件,重新上传可替换~</i> <i>你已成功添加附件,重新上传可替换~</i>
</span> </span>
</div> </div>
...@@ -81,8 +86,8 @@ ...@@ -81,8 +86,8 @@
</div> </div>
</template> </template>
<script> <script>
import { mapGetters } from 'vuex' import { mapGetters } from "vuex";
import { Toast,MessageBox } from 'mint-ui'; import { Toast, MessageBox } from "mint-ui";
import axios from "axios"; import axios from "axios";
export default { export default {
name: "workorder_detail", name: "workorder_detail",
...@@ -92,127 +97,167 @@ export default { ...@@ -92,127 +97,167 @@ export default {
isShowUploadLoading: false, isShowUploadLoading: false,
isSubmit: false, isSubmit: false,
workorder: {}, workorder: {},
comments:[], comments: [],
fileType: "", fileType: "",
request:{ request: {
file: "", file: "",
content: "", content: ""
} }
}; };
}, },
computed: { computed: {
...mapGetters([ ...mapGetters([
'isShowHeader', "isShowHeader",
'workorders', "workorders",
'userInfo', "userInfo",
'workorderTypes', "workorderTypes",
"uploadToken" "uploadToken"
]) ])
}, },
created() { created() {
document.title = "工单详细" document.title = "工单详细";
const id = this.$route.params.id const id = this.$route.params.id;
this.$store.commit("updateState", {isShowPageLoading: true}); this.$store.commit("updateState", { isShowPageLoading: true });
axios.all([this.getWorkOrder(id), this.getComments(id)]) axios.all([this.getWorkOrder(id), this.getComments(id)]).then(
.then(axios.spread(() => { axios.spread(() => {
this.$store.commit("updateState", {isShowPageLoading: false}); this.$store.commit("updateState", { isShowPageLoading: false });
})); })
);
}, },
methods: { methods: {
commentView(comment){ commentView(comment) {
var res = comment.match(/\[file=(.*)\]/) var res = comment.match(/\[file=(.*)\]/);
if(res == null) return comment if (res == null) return comment;
var fileType = res[1].substr(res[1].lastIndexOf('.')+1) var fileType = res[1].substr(res[1].lastIndexOf(".") + 1);
if("jpg,jpeg,png,JPG,JPEG,PNG".indexOf(fileType) != -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]+"' />") comment = comment.replace(
res[0],
"<br><img style='max-width:60%' preview='1' src='" + res[1] + "' />"
);
this.$previewRefresh(); this.$previewRefresh();
} }
return comment return comment;
}, },
getWorkOrder(id){ getWorkOrder(id) {
return axios.get("/public/workorder/"+id).then(response => { return axios
this.workorder = response.data.data .get("/public/workorder/" + id)
}).catch(error => { .then(response => {
console.log(error) this.workorder = response.data.data;
})
.catch(error => {
console.log(error);
}); });
}, },
getComments(id){ getComments(id) {
return axios.get("/public/workorder/comments/"+id).then(response => { return axios
if(response.data.data == null) return; .get("/public/workorder/comments/" + id)
this.comments = response.data.data .then(response => {
}).catch(error => { if (response.data.data == null) return;
console.log(error) this.comments = response.data.data;
})
.catch(error => {
console.log(error);
}); });
}, },
reply(){ reply() {
const content = this.request.content + this.request.file const content = this.request.content + this.request.file;
if(content.trim() == ''){ if (content.trim() == "") {
Toast({ Toast({
message: "请输入内容~" message: "请输入内容~"
}) });
return return;
} }
if(this.isSubmit) return if (this.isSubmit) return;
this.isSubmit = true this.isSubmit = true;
const wid = this.workorder.id const wid = this.workorder.id;
axios.post("/public/workorder/reply", {wid, content}).then(response => { axios
this.getComments(wid) .post("/public/workorder/reply", { wid, content })
.then(response => {
this.isSubmit = false
console.log(response);
this.getComments(wid);
this.request = { this.request = {
file: "", file: "",
content: "", content: ""
} };
}).catch(error => { })
.catch(error => {
this.isSubmit = false
console.log(error);
Toast({ Toast({
message: "提交失败~" message: "提交失败~"
})
}); });
});
}, },
inputBlur(){ inputBlur() {
  setTimeout(() => {  setTimeout(() => {
  document.body.scrollTo = 0; document.body.scrollTo = 0;
window.scrollTo(0, 0);   window.scrollTo(0, 0);
}, 100); }, 100);
}, },
uploadFile(e){ uploadFile(e) {
var fileDom = e.target; var fileDom = e.target;
var file = fileDom.files[0]; var file = fileDom.files[0];
this.isShowUploadLoading = true this.isShowUploadLoading = true;
const self = this const self = this;
this.$uploadFile({ this.$uploadFile({
file, file,
mode: this.uploadToken.mode, mode: this.uploadToken.mode,
// 七牛才会执行 // 七牛才会执行
percent(res) {}, percent() {},
success(src) { success(src) {
self.request.file = '[file=' + self.uploadToken.host + '/' + src + ']' self.request.file =
self.isShowUploadLoading = false "[file=" + self.uploadToken.host + "/" + src + "]";
self.isShowUploadLoading = false;
}, },
fail(e) { fail(e) {
self.isShowUploadLoading = false self.isShowUploadLoading = false;
if(e.response && e.response.data){ if (e.response && e.response.data) {
Toast({ Toast({
message: e.response.data.message message: e.response.data.message
}) });
return return;
} }
} }
}); });
}, },
close(){ close() {
var wid = this.workorder.id var wid = this.workorder.id;
MessageBox.confirm('您确定关闭该工单吗?').then(action => { MessageBox.confirm("您确定关闭该工单吗?").then(() => {
axios.put("/public/workorder/close/"+wid).then(response => { axios
.put("/public/workorder/close/" + wid)
.then(response => {
console.log(response);
Toast({ Toast({
message: "工单已关闭~" message: "工单已关闭~"
});
this.getWorkOrder(wid);
}) })
this.getWorkOrder(wid) .catch(error => {
}).catch(error => {
Toast({ Toast({
message: "工单关闭失败~" 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 { ...@@ -220,154 +265,181 @@ export default {
}; };
</script> </script>
<style lang="stylus" scoped> <style lang="stylus" scoped>
.container{ .container {
height 100vh height: 100vh;
overflow hidden overflow: hidden;
overflow-y auto overflow-y: auto;
} }
.content{
padding-top 50px .content {
padding-top: 50px;
padding-bottom: 90px; padding-bottom: 90px;
.no-data{
color #666 .no-data {
font-size 14px color: #666;
} font-size: 14px;
.workorder-close{ }
text-align center
color #666 .workorder-close {
font-size 14px text-align: center;
padding 10px color: #666;
} font-size: 14px;
&.hide-header{ padding: 10px;
padding-top 0 }
}
.head{ &.hide-header {
margin 0 10px padding-top: 0;
padding 10px 0 }
border-bottom 1px solid rgba(158, 158, 158, 0.13);
.con{ .head {
font-size 15px margin: 0 10px;
color #333 padding: 10px 0;
display flex border-bottom: 1px solid rgba(158, 158, 158, 0.13);
margin-bottom 8px
span{ .con {
flex-flow 1 font-size: 15px;
} color: #333;
span:first-child{ display: flex;
flex-flow 0 margin-bottom: 8px;
flex-shrink 0
width 45px span {
} flex-flow: 1;
i{ }
font-style normal
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 .file-view {
.avatar{ position: fixed;
padding-top 10px bottom: 80px;
img{ left: 0;
width 35px right: 0;
height 35px padding: 5px 10px;
border-radius 100px margin: 0 auto;
display block font-size: 13px;
} color: #8bc34a;
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;
span { span {
display flex display: flex;
align-content center align-content: center;
align-items center align-items: center;
img{
width 20px img {
height 20px width: 20px;
} height: 20px;
i{ }
font-style normal
margin-left 5px i {
} font-style: normal;
} margin-left: 5px;
} }
.input-form{ }
position fixed }
bottom 0
left 0 .input-form {
right 0 position: fixed;
margin 0 auto bottom: 0;
width 100% left: 0;
height 80px right: 0;
background-color #fff margin: 0 auto;
border-top 1px solid rgba(158, 158, 158, 0.13); width: 100%;
display flex height: 80px;
justify-content space-between background-color: #fff;
padding 0 10px border-top: 1px solid rgba(158, 158, 158, 0.13);
box-sizing border-box display: flex;
align-content center justify-content: space-between;
align-items center padding: 0 10px;
textarea{ box-sizing: border-box;
height 45px align-content: center;
flex-grow 1 align-items: center;
border-radius 0
border 0 textarea {
color #333 height: 45px;
font-size 14px flex-grow: 1;
resize none border-radius: 0;
} border: 0;
.icon-btn{ color: #333;
background url(./../assets/upload.png) center center no-repeat font-size: 14px;
background-size 30px resize: none;
}
.icon-btn {
background: url('./../assets/upload.png') center center no-repeat;
background-size: 30px;
width: 55px; width: 55px;
height 55px height: 55px;
overflow hidden overflow: hidden;
input{
display block input {
width 100% display: block;
height 100% width: 100%;
font-size 100px height: 100%;
opacity 0 font-size: 100px;
opacity: 0;
} }
} }
.sub-btn { .sub-btn {
display block display: block;
width: 55px; width: 55px;
height: 30px; height: 30px;
color: #fff; color: #fff;
...@@ -384,6 +456,6 @@ export default { ...@@ -384,6 +456,6 @@ export default {
} }
} }
} }
} }
</style> </style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment