You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

821 lines
25 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div>
<div class="cardTitle">
<a-space size="large">
<span>工单管理</span>
<a-radio-group v-model='activeName' button-style="solid" @change="tabsChange">
<a-radio-button :value="undefined">全部</a-radio-button>
<a-radio-button :value="1">待分配</a-radio-button>
<a-radio-button :value="2">工单池</a-radio-button>
<a-radio-button :value="3">已接单</a-radio-button>
<a-radio-button :value="4">处理中</a-radio-button>
<a-radio-button :value="5">待确认</a-radio-button>
<a-radio-button :value="6">待支付</a-radio-button>
<a-radio-button :value="7">已完成</a-radio-button>
<a-radio-button :value="8">已评价</a-radio-button>
<a-radio-button :value="9">已拒绝</a-radio-button>
<a-radio-button :value="10">已取消</a-radio-button>
</a-radio-group>
</a-space>
</div>
<div class="search-box">
<a-row>
<a-col :span="20">
<a-space size="large">
<a-select placeholder="工单类型" style="width:200px" v-model="form.workOrderTypeId" allowClear>
<a-select-option v-for="item,index in typeList" :key="index" :value="item.id">
{{item.name}}
</a-select-option>
</a-select>
<a-input placeholder="请输入工单号/姓名/手机号" style="width:200px" v-model="form.keyword">
</a-input>
<a-button type="primary" @click="onSearch">查 询</a-button>
<a-button @click="onReset">重 置</a-button>
</a-space>
</a-col>
<a-col :span="4">
<a-button class='add-btn' @click="show=true">添加工单</a-button>
<a-button @click="orderType=true">工单类型</a-button>
</a-col>
</a-row>
</div>
<div class="main">
<div style="margin-bottom: 16px">
<!-- 批量操作 -->
<a-select
type="primary"
v-model="activeAction"
:disabled="!hasSelected"
:loading="loading"
style="width: 120px"
@change="Actions"
placeholder="请选择操作"
>
批量
<a-select-option v-for="item in ActionsList" :key="item.value">
{{ item.label }}
</a-select-option>
</a-select>
<span style="margin-left: 8px">
<template v-if="hasSelected">
{{ `已选择 ${selectedRowKeys.length} 条` }}
</template>
</span>
</div>
<!-- 表格 -->
<a-table
:columns="columns"
:data-source="tableData"
:pagination="pagination"
:scroll="{ x: 2376 }"
@change="handleTableChange"
:row-selection="{
selectedRowKeys: selectedRowKeys,
onChange: selectionChoosed,
}"
:row-key="
(record, index) => {
return record.id;
}
"
>
<span slot="name" slot-scope="text, row">
{{
row.manageBuildingName +
"栋/" +
row.manageUnitName +
"单元/" +
row.floorLocation +
"层-" +
row.name +
"室"
}}
</span>
<span slot="action" slot-scope="text, row">
<a class="ant-dropdown-link" v-show="row.status===1" @click="put(row)">加入工单池</a>
<a class="ant-dropdown-link" v-show="row.status===2" @click="shift(row)">转移至待分配</a>
<!-- <a class="ant-dropdown-link" v-show="row.status===1 || row.status===2" @click="assign(row)">指派</a>
<a class="ant-dropdown-link" v-show="row.status===3 || row.status===4" @click="shiftAssign(row)">转派</a> -->
<a class="ant-dropdown-link" v-show="row.status===4" @click="finish(row)">完成</a>
<a class="ant-dropdown-link" v-show="row.status===4" @click="report(row)">汇报</a>
<a class="ant-dropdown-link" v-show="row.status===3" @click="deal(row)">处理</a>
<a class="ant-dropdown-link" v-show="row.status===5" @click="confirm(row)">确认</a>
<a class="ant-dropdown-link" v-show="row.status===6" @click="pay(row)">支付</a>
<a class="ant-dropdown-link" v-show="row.status===7 || row.status===8|| row.status===9|| row.status===10" @click="recall(row)">返单</a>
<a class="ant-dropdown-link" style="color: red" v-show="row.status===1|| row.status===2|| row.status===3|| row.status===4|| row.status===5 " @click="refuse(row)">取消</a>
</span>
<span slot="code" slot-scope="text,row">
<a @click="orderDetail(row.id)">{{row.code}}</a>
</span>
<span slot="tags" slot-scope="tag">
<a-tag :color="tag === 1 ? '#FF8C39' : tag === 2 ? '#921EAF' : tag === 4 ? '#205FBD' : tag === 8 ? 'rgba(0, 0, 0, 0.45)' : tag === 10 ? '#D53131' : 'grey'">
{{ tag === 1 ? "待分配" : tag === 2 ? "工单池" :tag === 3 ? "已接单" :tag === 4 ? "处理中" :tag === 5 ? "待确认" :tag === 6 ? "待支付"
:tag === 7 ? "已完成" :tag === 8 ? "已评价" :tag === 9 ? "已拒绝" :tag === 10 ? "已取消" :'-' }}
</a-tag>
</span>
<span slot="principal" slot-scope="text, row">
<span v-for="(item,index) in row.principal" :key="index">{{item}} </span>
</span>
<span slot="collaborator" slot-scope="text, row">
<span v-for="(item,index) in row.collaborator" :key="index">{{item}} </span>
</span>
</a-table>
</div>
<add-work :visible='show' @success="success" @onClose="onClose" :rules="rules"></add-work>
<trans-drawer @success="success" :assignId="assignId" :visible="transShow" @onClose="transClose"></trans-drawer>
<finish-drawer @success="success" :finishId="finishId" :visible="finishShow" @onClose="finishClose" ></finish-drawer>
<up-date-trans-drawer @success="success" :orderCode="orderCode" :updateTransId="updateTransId" :visible="updateTransShow" @onClose="updateTransClose"></up-date-trans-drawer>
<a-drawer title="工单设置" :width="720" :visible="orderType" :body-style="{ paddingBottom: '80px' }" @close="orderType=false">
<div class="drawer-content">
工单类型
<a-divider></a-divider>
<span v-for="item,index in typeList" :key="item.id">
<a-input v-if="item.show==true" ref="input" v-focus type="text" size="small"
:style="{ width: '78px','padding-bottom':'3px','margin-right':'7px' }"
v-model="item.name"
@blur="editType(item)"
@keyup.enter="editType(item)">
</a-input>
<a-tag v-else-if="item.show==false" closable @click="editInput(item, index)" @close.prevent="delType(item.id)">
{{item.name}}
</a-tag>
</span>
<span>
<a-input v-if="inputVisible" ref="addInput" type="text" size="small"
:style="{ width: '78px','padding-bottom':'3px'}"
:value="typeForm.name"
@change="handleInputChange"
@blur="handleInputConfirm"
@keyup.enter="handleInputConfirm">
</a-input>
<a-tag v-else style="background: #fff; borderStyle: dashed;" @click="addShow">
<a-icon type="plus" /> 新增类型
</a-tag>
</span>
</div>
<div class="drawer-footer">
<a-button :style="{ marginRight: '8px' }" @click="orderType=false">
关闭
</a-button>
</div>
</a-drawer>
<a-drawer title="工单结算" :width="720" :visible="payShow" :body-style="{ paddingBottom: '80px' }" @close="payClose">
<div class="drawer-content">
<a-form-model title="1d2" layout="vertical" ref="ruleForm" :wrapper-col="{ span: 18 }">
<div>工单账单</div>
<a-divider></a-divider>
<a-table :columns="payColumns" :data-source="payData.workOrderCostListVoList" :row-key="(record,index)=>{return record.id}">
<span slot="costType" slot-scope="text,record">
{{record.costType == 1 ? '人工费' : '耗材费'}}
</span>
<template slot="footer">
<span>总费用:{{payData.totalCost}}</span>
</template>
</a-table>
<a-row>
<a-col :span="12">
<a-form-model-item label="支付金额">
<a-input-number :min="0" :step="0.01" v-model="payForm.payPrice" placeholder="请输入支付金额" style="width: 200px"></a-input-number>
</a-form-model-item>
</a-col>
</a-row>
</a-form-model>
</div>
<div class="drawer-footer">
<a-button :style="{ marginRight: '8px' }" @click="payClose">取消</a-button>
<a-button type="primary" :style="{ marginRight: '8px' }" @click="payConfirm">确定</a-button>
</div>
</a-drawer>
<a-drawer title="提交报告" :width="720" :visible="repShow" :body-style="{ paddingBottom: '80px' }" @close="repClose">
<div class="drawer-content">
<a-form-model title="1d2" layout="vertical" ref="ruleForm" :wrapper-col="{ span: 18 }">
<a-row>
<a-col :span="24">
<a-form-model-item label="报告内容">
<a-textarea v-model="repForm.content"></a-textarea>
</a-form-model-item>
</a-col>
<a-col :span="12">
报告照片
<a-upload list-type="picture-card"
:action="`${$upload}`"
:headers="uploadHeaders"
accept='.jpg,.JPG,.png,.PNG,.jpeg,.JPEG'
@preview="handlePreview"
@change="picChange"
:file-list="headList"
:beforeUpload="beforeUpload">
<div v-if="headList.length < 1">
<a-icon type="plus" />
<div class="ant-upload-text">上传照片</div>
</div>
</a-upload>
</a-col>
</a-row>
<div>工单进度</div>
<a-divider></a-divider>
<a-timeline>
<a-timeline-item v-for="(item, index) in repData" :key="index">
<template>
<a-tag>{{repStatus[item.status]}}</a-tag>
<div>{{item.createDate}}</div>
<div>{{item.userType==1?'申请人':2?'分配人':3?'负责人':4?'管理员':'协同人'}}{{item.createName}}</div>
<div>{{item.content}}</div>
</template>
</a-timeline-item>
</a-timeline>
</a-form-model>
</div>
<div class="drawer-footer">
<a-button :style="{ marginRight: '8px' }" @click="repClose">取消</a-button>
<a-button type="primary" :style="{ marginRight: '8px' }" @click="repConfirm">确定</a-button>
</div>
</a-drawer>
<a-drawer title="工单详情" :width="720" :visible="detailShow" :body-style="{ paddingBottom: '80px' }" @close="detailClose">
<div class="drawer-content">
<div class="order-detail-title">工单编号
<span style="float: right;color: rgba(0, 0, 0, 0.45)">来源:{{detailData.workOrderInfo.froms==1?'后台':2?'app':'管家app'}}</span>
</div>
<div class="order-detail-title">{{detailData.workOrderInfo.code}}
<a-tag style="margin-left: 16px">{{repStatus[detailData.workOrderInfo.status]}}</a-tag>
</div>
<a-divider></a-divider>
<a-descriptions layout="vertical" style="margin-left: 6px">
<a-descriptions-item label="申请人">{{detailData.workOrderInfo.applicantName}}</a-descriptions-item>
<a-descriptions-item label="申请人身份">{{detailData.workOrderInfo.identity==1?'住户':'物业'}}</a-descriptions-item>
<a-descriptions-item label="联系方式">{{}}</a-descriptions-item>
<a-descriptions-item label="关联房屋">
{{detailData.workOrderInfo.buildingName}}-{{detailData.workOrderInfo.unitName}}-{{detailData.workOrderInfo.estateName}}
</a-descriptions-item>
<a-descriptions-item label="工单类型">{{detailData.workOrderInfo.workOrderTypeName}}</a-descriptions-item>
<a-descriptions-item label="预约到场时间">{{detailData.workOrderInfo.reserveDate}}</a-descriptions-item>
<a-descriptions-item label="具体地址">{{detailData.workOrderInfo.reserveAddress}}</a-descriptions-item>
</a-descriptions>
<a-descriptions layout="vertical" :column="1" style="margin-left: 6px">
<a-descriptions-item label="工单内容">
<div style="display: flex">
<img v-for="(item,index) in detailData.workOrderInfo.imgList"
:key="index" :src="$ImgUrl(item.url)" style="height: 86px;width: 86px" />
</div>
<div style="margin-top: 16px">{{detailData.workOrderInfo.content}}</div>
</a-descriptions-item>
</a-descriptions>
<div class="order-detail-title">工单账单</div>
<a-divider></a-divider>
<a-table :columns="payColumns" :data-source="detailData.workOrderCostList">
<span slot="costType" slot-scope="text,record">
{{record.costType == 1 ? '人工费' : '耗材费'}}
</span>
<span slot="footer">
总价格:{{detailTotalCost}}
</span>
</a-table>
<div class="order-detail-title">工单进度</div>
<a-divider></a-divider>
<a-timeline :reverse="true">
<a-timeline-item v-for="(item, index) in detailData.workOrderScheduleList" :key="index">
<template>
<a-tag>{{repStatus[item.status]}}</a-tag>
<div>
{{ (new Date(item.createDate)).toLocaleString() }}
{{ (new Date(item.createDate)).getUTCDay()==1?'一':2?'二':3?'三':4?'四':5?'五':6?'六':'日'}}
</div>
<div>{{item.userType==1?'申请人':2?'分配人':3?'负责人':4?'管理员':'协同人'}}{{item.createName}}</div>
<div>{{item.content}}</div>
</template>
</a-timeline-item>
</a-timeline>
</div>
<div class="drawer-footer">
<a-button :style="{ marginRight: '8px' }" type="danger" ghost @click="detailClose"></a-button>
</div>
</a-drawer>
</div>
</template>
<script>
import uploadHeaders from "./form.js"
import {getAllWorkOrder} from "@/api/basic/Workorder"
import {getAllWorkOrderType} from "@/api/basic/Workorder"
import {AddWorkOrderType, EditWorkOrderType, DelWorkOrderType} from "@/api/basic/Workorder"
import {cancelWorkOrder, joinTicketPool, moveToAssignment, process, confirm, settlement, report} from "@/api/basic/Workorder"
import addWork from "../WorkOrder/addWorkOrder.vue"
import transDrawer from "../WorkOrder/transDrawer.vue"
import finishDrawer from "../WorkOrder/finishDrawer.vue"
import upDateTransDrawer from "../WorkOrder/upDateTransDrawer.vue"
import {getDetail, workOrderCostList, orderSchedule} from "@/api/basic/Workorder"
export default {
components:{
addWork,
transDrawer,
finishDrawer,
upDateTransDrawer
},
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
},
data() {
return {
uploadHeaders,
headList: [],
form:{
pageNum: 1,
size: 10,
status: undefined,
workOrderTypeId: undefined,
keyword: ''
},
typeForm: {
name: '',
id: undefined
},
rules:{},
show: false,
activeName:'0',
pagination: {
current: 1,
total: 0,
pageSize: 10,
showTotal: (total) => `${total}`,
showSizeChanger: true,
showQuickJumper: true,
},
searchForm:{
status:null,
identity:null
},
activeAction: undefined,
loading: false,
// 选择的index
selectedRowKeys: [],
tableChoosed: [],
// 分页
// 列
columns: [
{
title: "工单状态",
key: "tags",
dataIndex: "status",
width: 117,
scopedSlots: { customRender: "tags" },
},
{
title: "工单号",
dataIndex: "code",
width: 215,
scopedSlots: { customRender: "code" },
},
{
title: "申请人",
width: 117,
dataIndex: "applicantName",
},
{
title: "手机号",
width: 157,
dataIndex: "applicantTel",
},
{
title: "工单类型",
width: 155,
dataIndex: "workOrderTypeName",
},
{
title: "工单内容",
width: 326,
dataIndex: "content",
},
{
title: "具体地址",
width: 220,
dataIndex: "reserveAddress",
},
{
title: "负责人",
width: 166,
dataIndex: "principal",
scopedSlots: { customRender: "principal" },
},
{
title: "协同人",
width: 246,
dataIndex: "collaborator",
scopedSlots: { customRender: "collaborator" },
},
{
title: "任务开始时间",
width: 266,
dataIndex: "reserveDate",
},
{
title: "操作",
dataIndex: "action",
key: "action",
width: 220,
fixed: "right",
scopedSlots: { customRender: "action" },
},
],
payColumns: [
{
title: "收费类型",
dataIndex: "costType",
key: "costType",
scopedSlots: { customRender: "costType" },
},
{
title: "收费名称",
dataIndex: "name",
key: "name",
},
{
title: "数量",
dataIndex: "num",
key: "num",
},
{
title: "价格(单价)",
dataIndex: "price",
key: "price",
},
],
// 数据
tableData: [],
ActionsList: [
{
label: "批量删除",
value: 1,
},
{
label: "批量导出",
value: 2,
},
],
//工单类型抽屉
typeList: [],
orderType: false,
inputVisible: false,
//指派抽屉
transShow: false,
assignId: undefined,
//完成抽屉
finishShow: false,
finishId: undefined,
//转派抽屉
updateTransShow: false,
updateTransId: undefined,
orderCode: '',
//支付抽屉
payShow: false,
payData: {},
payForm: {workOrderId: undefined, payPrice: 0},
//汇报抽屉
repShow: false,
repData: [],
repForm: {workOrderId: undefined, content: '', imgUrls: []},
repStatus: ['','待分配','工单池','已接单','处理中','待确认','待支付','已完成','已评价','已拒绝','已取消'],
//详情抽屉
detailData: {
workOrderCostList: [],
workOrderInfo: {},
workOrderScheduleList: {}
}, //workOrderCostList, workOrderInfo, workOrderScheduleList
detailShow: false,
detailTotalCost: 0
};
},
mounted(){
this.getApi()
this.getData()
},
methods: {
getApi() {
getAllWorkOrderType().then(res => {
let data = res.data;
data.forEach(ele => {
ele.show = false;
});
this.typeList = data;
})
},
getData() {
getAllWorkOrder(this.form).then(res => {
this.tableData = res.data.rows;
this.pagination.total = res.data.total;
})
},
onSearch() {
this.getData()
},
onReset() {
this.form.workOrderTypeId = undefined;
this.form.keyword = undefined;
this.getData();
},
tabsChange(e){
this.form.status = e.target.value
this.getData()
},
onClose(){
this.show = false;
},
// 详情
orderDetail(id) {
getDetail({manageWorkOrderId: id}).then(res => {
let data = res.data;
this.detailData = data
let detailTotalCost = 0;
data.workOrderCostList.forEach(ele => {
let p = ele.num * ele.price;
detailTotalCost = detailTotalCost + p;
})
this.detailTotalCost = detailTotalCost
});
this.detailShow = true;
},
// 加入工单池
put(val){
this.$confirm({
title: "是否加入工单池",
icon:'plus',
onOk:async()=>{
let res = await joinTicketPool({manageWorkOrderId: val.id})
if(res.code === 200){
this.$message.success(res.msg);
this.getData()
} else {
this.$message.error(res.msg);
}
},
})
},
// 转移至待分配
shift(val){
this.$confirm({
title: "是否转移至待分配",
icon:'redo',
onOk:async()=>{
let res = await moveToAssignment({manageWorkOrderId: val.id})
if(res.code === 200){
this.$message.success(res.msg);
this.getData()
} else {
this.$message.error(res.msg);
}
},
})
},
// 指派
assign(val){
this.assignId = val.id;
this.transShow = true;
},
// 转派
shiftAssign(val){
this.orderCode = val.code;
this.updateTransId = val.id;
this.updateTransShow = true;
},
// 完成
finish(val){
this.finishId = val.id;
this.finishShow = true;
},
// 处理
deal(val){
this.$confirm({
title: "是否处理",
icon:'tool',
onOk:async()=>{
let res = await process({manageWorkOrderId: val.id})
if(res.code === 200){
this.$message.success(res.msg);
this.getData()
} else {
this.$message.error(res.msg);
}
},
})
},
// 确认
confirm(val) {
this.$confirm({
title: "是否确认",
icon:'check',
onOk:async()=>{
let res = await confirm({manageWorkOrderId: val.id})
if(res.code === 200){
this.$message.success(res.msg);
this.getData()
} else {
this.$message.error(res.msg);
}
},
})
},
// 汇报
report(val) {
this.repShow = true;
this.repForm.workOrderId = val.id;
orderSchedule({manageWorkOrderId: val.id}).then(res => {
let data = res.data;
this.repData = data
})
},
repConfirm() {
// 照片
let pic = []
for(let item of this.headList){
// 新增的照片
if(item.response){
pic.push(item.response.data)
}else{
// 已添加的照片
pic.push(item.url.split('/')[item.url.split('/').length-1])
}
};
this.repForm.imgUrls = pic
report(this.repForm).then(res => {
if(res.code === 200){
this.$message.success(res.msg);
this.getData()
} else {
this.$message.error(res.msg);
}
});
this.repShow = false;
this.repData = [];
this.headList = [];
},
// 支付
pay(val) {
this.payShow = true;
this.payForm.workOrderId = val.id;
workOrderCostList({manageWorkOrderId: val.id}).then(res => {
let data = res.data;
this.payData = data;
})
},
payConfirm() {
settlement(this.payForm).then(res => {
if(res.code=== 200){
this.$message.success(res.msg);
this.getData()
} else {
this.$message.error(res.msg);
}
});
this.payShow = false;
this.payData = {};
this.payForm.payPrice = 0;
},
// 返单
recall() {
},
// 取消
refuse(val){
this.$confirm({
title: "是否删除",
icon:'delete',
onOk:async()=>{
let res = await cancelWorkOrder({workOrderIds: [val.id]})
if(res.code=== 200){
this.$message.success(res.msg);
this.getData()
}else{
this.$message.error(res.msg);
}
},
})
},
handleTableChange(pagination) {
console.log(pagination);
const pager = { ...this.pagination };
pager.current = pagination.current;
pager.pageSize = pagination.pageSize;
this.pagination = pager;
this.getData()
},
Actions(data) {
console.log(data);
this.activeAction = undefined;
},
selectionChoosed(data) {
console.log(data);
this.tableChoosed = data;
},
//添加工单类型
addShow() {
this.inputVisible = true;
this.$nextTick(function() {
this.$refs.addInput.focus();
});
},
handleInputChange(e) {
this.typeForm.name = e.target.value;
},
handleInputConfirm() {
if(this.typeForm.name === ''){
this.inputVisible = false;
return
};
AddWorkOrderType({name: this.typeForm.name}).then(res => {
this.$message.success(res.msg);
this.inputVisible = false;
this.getApi();
this.typeForm.name = ''
})
},
//编辑工单类型
editInput(obj, i) {
this.$set(this.typeList[i],'show',true)
this.$forceUpdate()
},
editType(item) {
let obj = {
id: item.id,
name: item.name
}
EditWorkOrderType(obj).then(res => {
if(res.code === 200){
item.show = false
this.$forceUpdate()
this.$message.success(res.msg)
} else {
this.$message.error(res.msg)
}
})
},
//删除工单类型
delType(id) {
this.$confirm({
title: "是否删除",
icon:'delete',
onOk:async()=>{
let res = await DelWorkOrderType({workOrderTypeIds:[id]})
if(res.code=== 200){
this.$message.success(res.msg);
this.getApi()
}else{
this.$message.error(res.msg);
}
},
})
},
// form提交成功的回调
close() {
this.show = false;
},
// form提交成功的回调
success() {
this.getData();
},
//抽屉关闭
transClose() {this.transShow = false;},
finishClose() {this.finishShow = false;},
updateTransClose() {this.updateTransShow = false;},
payClose() {this.payShow = false},
repClose() {this.repShow = false},
detailClose() {this.detailShow = false},
//图片上传
beforeUpload(f,l) {
const isLt50M = f.size / 1024 / 1024 < 50;
if (!isLt50M) {
this.$message.error(f.name + "文件大小超出限制,请修改后重新上传");
return false;
} else {
return true;
}
},
picChange(info){
this.headList = info.fileList
},
handlePreview() {
}
},
computed: {
// 是否选择selection
hasSelected() {
return this.selectedRowKeys.length > 0;
},
},
};
</script>
<style lang="less" scoped>
.ant-dropdown-link {
margin-left: 8px;
}
.order-detail-title {
padding: 8px;
size :16px;
font-weight: bold;
}
</style>