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() {
}, },
mounted() {}, methods: {
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(_)
},
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> </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,8 +7,11 @@ ...@@ -7,8 +7,11 @@
<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">
<div class="con"> <div class="con">
<span>标题:</span> <span>标题:</span>
...@@ -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,298 +97,365 @@ export default { ...@@ -92,298 +97,365 @@ 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 })
this.request = { .then(response => {
file: "", this.isSubmit = false
content: "", console.log(response);
} this.getComments(wid);
}).catch(error => { this.request = {
Toast({ file: "",
message: "提交失败~" content: ""
};
}) })
}); .catch(error => {
this.isSubmit = false
console.log(error);
Toast({
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) { },
self.isShowUploadLoading = false fail(e) {
if(e.response && e.response.data){ self.isShowUploadLoading = false;
Toast({ if (e.response && e.response.data) {
message: e.response.data.message Toast({
}) 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 => {
Toast({
message: "工单关闭失败~"
}) })
console.log(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));
})
.catch(error => {
Toast({
message: "工单关闭失败~"
});
console.log(error);
});
}); });
} }
} }
}; };
</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;
padding-bottom: 90px;
.no-data {
color: #666;
font-size: 14px;
} }
.content{
padding-top 50px .workorder-close {
padding-bottom: 90px; text-align: center;
.no-data{ color: #666;
color #666 font-size: 14px;
font-size 14px padding: 10px;
} }
.workorder-close{
text-align center &.hide-header {
color #666 padding-top: 0;
font-size 14px }
padding 10px
} .head {
&.hide-header{ margin: 0 10px;
padding-top 0 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;
}
} }
.head{ }
margin 0 10px
padding 10px 0 .comments {
border-bottom 1px solid rgba(158, 158, 158, 0.13); padding: 10px;
.con{
font-size 15px .item {
color #333 display: flex;
display flex
margin-bottom 8px .avatar {
span{ padding-top: 10px;
flex-flow 1
} img {
span:first-child{ width: 30px;
flex-flow 0 height: 30px;
flex-shrink 0 border-radius: 100px;
width 45px display: block;
}
i{
font-style normal
} }
border-bottom: 1px solid rgba(158, 158, 158, 0.13);
} }
} .right {
.comments{ padding: 10px 5px;
padding 10px flex-grow: 1;
.item{ border-bottom: 1px solid rgba(158, 158, 158, 0.13);
display flex
.avatar{ .nickname {
padding-top 10px font-size: 15px;
img{ color: #333;
width 35px
height 35px
border-radius 100px
display block
}
border-bottom 1px solid rgba(158, 158, 158, 0.13);
} }
.right{
padding 10px 5px .detail {
flex-grow 1 font-size: 15px;
border-bottom 1px solid rgba(158, 158, 158, 0.13); color: #333;
.nickname{ margin-top: 5px;
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{ .date {
border-bottom 0 color: #999;
} font-size: 14px;
margin-top: 5px;
} }
} }
}
.file-view{ &:last-child {
position fixed .right, .avatar {
bottom 80px border-bottom: 0;
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 .file-view {
left 0 position: fixed;
right 0 bottom: 80px;
margin 0 auto left: 0;
width 100% right: 0;
height 80px padding: 5px 10px;
background-color #fff margin: 0 auto;
border-top 1px solid rgba(158, 158, 158, 0.13); font-size: 13px;
display flex color: #8bc34a;
justify-content space-between
padding 0 10px span {
box-sizing border-box display: flex;
align-content center align-content: center;
align-items center align-items: center;
textarea{
height 45px img {
flex-grow 1 width: 20px;
border-radius 0 height: 20px;
border 0
color #333
font-size 14px
resize none
} }
.icon-btn{
background url(./../assets/upload.png) center center no-repeat i {
background-size 30px font-style: normal;
width: 55px; margin-left: 5px;
height 55px
overflow hidden
input{
display block
width 100%
height 100%
font-size 100px
opacity 0
}
} }
.sub-btn { }
display block }
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 { .input-form {
opacity: 0.8; 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;
}
}
.sub-btn {
display: block;
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;
} }
} }
} }
}
</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