543 lines
18 KiB
Vue
543 lines
18 KiB
Vue
<template>
|
|
<view class="ctr" v-if="data !== null">
|
|
<view class="price-ctr">
|
|
<view class="price flex-c" v-if="data.order_info.receive_type === 1">上门报价</view>
|
|
<view class="price flex-c" v-else>平台已收款</view>
|
|
<view class="desc flex-c">{{ getPriceDescText() }}</view>
|
|
</view>
|
|
|
|
<view class="info" v-if="data.status !== enums.ORDER_DISPATCH_STATUS.STATUS_TOGET">
|
|
<view class="item-multi-line">
|
|
<view class="title flex-l title-class">我的备注 <text v-if="data.worker_remark" class="description flex-l">仅自己可见,点击备注可修改</text></view>
|
|
<view @click="updateWorkerRemark()">
|
|
<view class="value flex-l placeholder-class" v-if="data.worker_remark === ''">您可在此处输入备注信息,该备注信息仅自己可见</view>
|
|
<view class="value flex-l" v-else>{{ data.worker_remark }}</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="info">
|
|
<view class="item-row flex-sb line-after">
|
|
<view class="title flex-l">订单编号</view>
|
|
<view class="value flex-r value-theme">
|
|
<text>{{ data.order_info.order_no }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="item-row flex-sb line-after">
|
|
<view class="title flex-l">当前状态</view>
|
|
<view class="value flex-r order-status">
|
|
<text>{{getOrderStatusText(data.status)}}</text>
|
|
</view>
|
|
</view>
|
|
<view class="item-row flex-sb line-after">
|
|
<view class="title flex-l">服务类型</view>
|
|
<view class="value flex-r">
|
|
<text>{{data.order_info.item_title}}</text>
|
|
</view>
|
|
</view>
|
|
<template v-if="data.status !== enums.ORDER_DISPATCH_STATUS.STATUS_TOGET">
|
|
<view class="item-row flex-sb line-after">
|
|
<view class="title flex-l">客户姓名</view>
|
|
<view class="value flex-r">
|
|
<text>{{ data.order_info.customer }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="item-row flex-sb line-after">
|
|
<view class="title flex-l">客户电话</view>
|
|
<view v-if="data.status === enums.ORDER_DISPATCH_STATUS.STATUS_FINISH" class="value flex-r">
|
|
<text>{{ data.order_info.tel }}</text>
|
|
</view>
|
|
<view v-else class="value flex-r value-theme" @click="helpers.makePhoneCall(data.order_info.tel)">
|
|
<text>{{ data.order_info.tel }}</text>
|
|
<me-icon class="icon" type="icon-call" color="var(--themeColor)" size="40rpx"></me-icon>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
<view class="item-row flex-sb line-after">
|
|
<view class="title flex-l">预约上门时间</view>
|
|
<view class="value flex-r value-theme" v-if="data.status === enums.ORDER_DISPATCH_STATUS.STATUS_PLANIT">
|
|
<uni-datetime-picker type="datetime" :start="Date.now()" :hide-second="true" @change="changePlanTime">
|
|
<view class="flex-r">
|
|
<text>{{data.plan_time}}</text>
|
|
<me-icon class="icon" type="icon-edit-line" color="var(--themeColor)" size="40rpx"></me-icon>
|
|
</view>
|
|
</uni-datetime-picker>
|
|
</view>
|
|
<view v-else class="value flex-r">
|
|
<text>{{data.plan_time}}</text>
|
|
</view>
|
|
</view>
|
|
<view class="item-multi-line line-after">
|
|
<view class="title flex-l">客户地址</view>
|
|
<view class="value flex-l">{{helpers.removeCommas(data.order_info.area.merge_name)}}{{ data.order_info.address }}</view>
|
|
</view>
|
|
<view class="item-multi-line line-after">
|
|
<view class="title flex-l">订单详情</view>
|
|
<view class="value flex-l">{{data.order_info.detail ? data.order_info.detail : '暂无详情'}}</view>
|
|
</view>
|
|
<view class="images line-after" v-if="data.order_info.images.length > 0">
|
|
<view class="title flex-l">图片</view>
|
|
<view class="imgs-ctr">
|
|
<view @click="helpers.previewImage(imgUrl)" v-for="(imgUrl, index) in data.order_info.images" :key="index" class="img-ctr" :style="{marginRight: (index+1) % 4 === 0 ? '0' : '55rpx'}">
|
|
<image class="img" mode="aspectFit" :src="imgUrl"></image>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="item-multi-line line-after">
|
|
<view class="title flex-l">平台备注</view>
|
|
<view class="value flex-l">{{data.order_info.remark ? data.order_info.remark : '无备注信息'}}</view>
|
|
</view>
|
|
<view class="report-order-exception flex-c" v-if="canReportOrderException">
|
|
<view @click="reportOrderException(data.order_info.id)" class="report-ctr flex-c" hover-class="auto-mask-layer-radius4" hover-start-time="0" hover-stay-time="50">
|
|
<me-icon type="icon-arrow-up-line" color="var(--importantColor)" size="36rpx"></me-icon>
|
|
<text class="text">上报异常</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 已拒接-->
|
|
<view class="info" v-if="data.status === enums.ORDER_DISPATCH_STATUS.STATUS_REFUSED">
|
|
<view class="item-multi-line">
|
|
<view class="title flex-l">拒接原因</view>
|
|
<view class="value flex-l">{{data.reject_reason ? data.reject_reason : '未填写原因'}}</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 已上门、已完成 显示上门时间-->
|
|
<view class="info" v-if="[enums.ORDER_DISPATCH_STATUS.STATUS_CLOCK, enums.ORDER_DISPATCH_STATUS.STATUS_FINISH].includes(data.status)">
|
|
<view class="item-row flex-sb line-after">
|
|
<view class="title flex-l">上门时间</view>
|
|
<view class="value flex-r">
|
|
<text>{{data.arrive_time}}</text>
|
|
</view>
|
|
</view>
|
|
<view class="images">
|
|
<view class="title flex-l">上门图片</view>
|
|
<view class="imgs-ctr">
|
|
<view @click="helpers.previewImage(imgUrl)" v-for="(imgUrl, index) in data.arrive_images" :key="index" class="img-ctr" :style="{marginRight: (index+1) % 4 === 0 ? '0' : '55rpx'}">
|
|
<image class="img" mode="aspectFit" :src="imgUrl"></image>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 已完成 -->
|
|
<view class="info" v-if="data.status === enums.ORDER_DISPATCH_STATUS.STATUS_FINISH">
|
|
<view class="item-row flex-sb line-after">
|
|
<view class="title flex-l">完成时间</view>
|
|
<view class="value flex-r">
|
|
<text>{{data.finish_time}}</text>
|
|
</view>
|
|
</view>
|
|
<view :class="[data.order_info.receive_type === 1 ? 'line-after' : '', 'images']">
|
|
<view class="title flex-l">完成图片</view>
|
|
<view class="imgs-ctr">
|
|
<view @click="helpers.previewImage(imgUrl)" v-for="(imgUrl, index) in data.images" :key="index" class="img-ctr" :style="{marginRight: (index+1) % 5 === 0 ? '0' : '36rpx'}">
|
|
<image class="img" mode="aspectFit" :src="imgUrl"></image>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="item-row flex-sb line-after">
|
|
<view class="title flex-l">是否使用材料</view>
|
|
<view class="value flex-r">
|
|
<text>{{ data.order_info.is_material_used === 1 ? '已使用' : '未使用' }}</text>
|
|
</view>
|
|
</view>
|
|
<template v-if="data.order_info.is_material_used === 1">
|
|
<view class="item-row flex-sb line-after">
|
|
<view class="title flex-l">材料成本</view>
|
|
<view class="value flex-r">
|
|
<text>¥{{ data.order_info.material_cost }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="line-after images">
|
|
<view class="title flex-l">材料凭证</view>
|
|
<view class="imgs-ctr">
|
|
<view @click="helpers.previewImage(imgUrl)" v-for="(imgUrl, index) in data.order_info.material_images" :key="index" class="img-ctr" :style="{marginRight: (index+1) % 5 === 0 ? '0' : '36rpx'}">
|
|
<image class="img" mode="aspectFit" :src="imgUrl"></image>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
<template v-if="data.order_info.receive_type === 1">
|
|
<view class="item-row flex-sb line-after" v-if="data.order_info.receive_type === 1">
|
|
<view class="title flex-l">优惠信息</view>
|
|
<view class="value flex-r">
|
|
<text>{{data.order_info.online_amount}}元抵扣{{data.order_info.discount_amount}}元</text>
|
|
</view>
|
|
</view>
|
|
<view class="item-row flex-sb line-after" v-if="data.offline_total_type !== 0">
|
|
<view class="title flex-l">尾款收款方</view>
|
|
<view class="value flex-r">
|
|
<text>{{ data.offline_total_type === 1 ? '师傅收' : '公司收' }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="item-row flex-sb line-after">
|
|
<view class="title flex-l">收款金额</view>
|
|
<view class="value flex-r">
|
|
<text>¥{{ data.total > 0 ? data.total : data.online_total }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="images">
|
|
<view class="title flex-l">收款凭证</view>
|
|
<view class="imgs-ctr">
|
|
<view @click="helpers.previewImage(data.image)" :key="index" class="img-ctr">
|
|
<image class="img" mode="aspectFit" :src="data.image"></image>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
</view>
|
|
|
|
<me-empty-space height="376"></me-empty-space>
|
|
|
|
<!-- 待接单-->
|
|
<view class="bottom" v-if="data.status === enums.ORDER_DISPATCH_STATUS.STATUS_TOGET">
|
|
<me-button @click="acceptOrder()" text="确认接单" width="686rpx" icon-type="icon-flashlight"></me-button>
|
|
<me-button @click="rejectOrder()" active-color="rgba(0, 0, 0, 0)" margin-top="32rpx" text="拒 绝" width="686rpx" text-color="var(--titleColor)"></me-button>
|
|
</view>
|
|
|
|
<!-- 待和客户确认上门时间-->
|
|
<view class="bottom" v-if="data.status === enums.ORDER_DISPATCH_STATUS.STATUS_GOTIT">
|
|
<me-button @click="selectTime()" text="已和客户沟通" width="686rpx" icon-type="icon-arrow-right-circle" margin-top="32rpx"></me-button>
|
|
</view>
|
|
|
|
<!-- 待上门-->
|
|
<view class="bottom" v-if="data.status === enums.ORDER_DISPATCH_STATUS.STATUS_PLANIT">
|
|
<me-button @click="helpers.openLocation(data.order_info.lat, data.order_info.lng)" active-color="var(--contentBgColor)" icon-type="icon-navigation" text="导航至客户地址" width="686rpx" text-color="var(--titleColor)" custom-icon-color="var(--titleColor)"></me-button>
|
|
<me-button @click="arrivedOnSite()" text="到达现场" width="686rpx" icon-type="icon-arrow-right-circle" margin-top="32rpx"></me-button>
|
|
</view>
|
|
|
|
<!-- 完成服务-->
|
|
<view class="bottom" v-if="data.status === enums.ORDER_DISPATCH_STATUS.STATUS_CLOCK">
|
|
<me-button @click="updateProgress()" active-color="var(--importantColor)" text="更新施工进度" width="686rpx" custom-icon-color="var(--titleColor)"></me-button>
|
|
<me-button @click="completeService()" text="完成服务" width="686rpx" icon-type="icon-arrow-right-circle" margin-top="32rpx"></me-button>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
|
|
import MeIcon from "../../components/me-icon/me-icon.vue";
|
|
import MeEmptySpace from "../../components/me-empty-space/me-empty-space.vue";
|
|
import MeButton from "../../components/me-button/me-button.vue";
|
|
import helpers from "../../utils/helpers";
|
|
import {onLoad, onShow} from '@dcloudio/uni-app'
|
|
import {ref, computed} from 'vue'
|
|
import api from "../../api/api";
|
|
import enums from "../../utils/enums";
|
|
|
|
const updateProgress = () => {
|
|
helpers.jumpToPage('update-progress', 'id=' + id.value)
|
|
}
|
|
|
|
//是否可上报异常,未接单和已拒接的无法上报
|
|
const canReportOrderException = computed(() => {
|
|
const excludedStatuses = [
|
|
enums.ORDER_DISPATCH_STATUS.STATUS_TOGET,
|
|
enums.ORDER_DISPATCH_STATUS.STATUS_REFUSED,
|
|
enums.ORDER_DISPATCH_STATUS.STATUS_FINISH
|
|
];
|
|
|
|
return !excludedStatuses.includes(data.value.status);
|
|
})
|
|
|
|
const changePlanTime = (time) => {
|
|
uni.showModal({
|
|
title: '提示信息',
|
|
content: '修改前需和客户约定,确定修改上门时间?',
|
|
success: function (res) {
|
|
if (res.confirm) {
|
|
api.updatePlanTime({order_dispatch_id: id.value, plan_time: time}).then(() => {
|
|
helpers.delayHideLoading()
|
|
uni.showToast({
|
|
title: '修改成功',
|
|
icon: "success"
|
|
})
|
|
data.value.plan_time = time + ':00'
|
|
}).catch(() => {})
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
//更新师傅备注
|
|
const updateWorkerRemark = () => {
|
|
helpers.jumpToPage('worker-remark', `id=${id.value}&worker_remark=${data.value.worker_remark}`)
|
|
}
|
|
|
|
//上报异常
|
|
const reportOrderException = (orderId) => {
|
|
helpers.jumpToPage('report-order-exception', `order_id=${orderId}`)
|
|
}
|
|
|
|
//完成上门
|
|
const arrivedOnSite = () => {
|
|
//获取师傅当前位置
|
|
uni.getLocation({
|
|
type: 'gcj02',
|
|
success(res) {
|
|
let envVersion = wx.getAccountInfoSync().miniProgram.envVersion
|
|
|
|
let distances = helpers.getDistances(res.latitude, res.longitude, data.value.order_info.lat, data.value.order_info.lng);
|
|
if (envVersion === 'release' && (distances.unit === '公里' || distances.distance > 500)) {
|
|
uni.showModal({
|
|
title: '上门失败',
|
|
showCancel: false,
|
|
content: `距离客户地址超过 500 米,当前距离:${distances.distance}${distances.unit}`,
|
|
success: function (res) {
|
|
}
|
|
});
|
|
return
|
|
}
|
|
|
|
helpers.jumpToPage('arrived-on-site', 'id=' + id.value)
|
|
},
|
|
fail(err) {
|
|
uni.showToast({
|
|
title: '请授权位置权限',
|
|
icon: "error"
|
|
})
|
|
}
|
|
});
|
|
}
|
|
|
|
//完成服务
|
|
const completeService = () => {
|
|
helpers.jumpToPage('complete-service', 'id=' + id.value)
|
|
}
|
|
|
|
//选择上门时间
|
|
const selectTime = () => {
|
|
helpers.jumpToPage('select-time', 'id=' + id.value)
|
|
}
|
|
|
|
const acceptOrder = () => {
|
|
uni.showModal({
|
|
title: '接单提示',
|
|
confirmText: '确认',
|
|
content: '接单后请及时和客户联系,确认接单?',
|
|
success: function (res) {
|
|
if (res.confirm) {
|
|
api.orderConfirm({type: 'accept', order_dispatch_id: id.value}).then(() => {
|
|
helpers.showToast('已接单')
|
|
init()
|
|
}).catch(() => {})
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
const rejectOrder = () => {
|
|
uni.showModal({
|
|
title: '拒接提示',
|
|
confirmText: '确认',
|
|
editable: true,
|
|
placeholderText: '请输入拒接原因',
|
|
success: function (res) {
|
|
if (res.confirm) {
|
|
if (!res.content) {
|
|
return helpers.showToast('请输入拒接原因')
|
|
}
|
|
|
|
api.orderConfirm({type: 'reject', order_dispatch_id: id.value, reject_reason: res.content}).then(() => {
|
|
helpers.showToast('已拒接')
|
|
init()
|
|
}).catch(() => {})
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
const id = ref(null)
|
|
onLoad((params) => {
|
|
id.value = params.id
|
|
})
|
|
|
|
onShow(() => {
|
|
init()
|
|
})
|
|
|
|
const data = ref(null)
|
|
const init = () => {
|
|
uni.showLoading({
|
|
title: '加载中'
|
|
});
|
|
api.orderInfo({order_dispatch_id: id.value}).then(res => {
|
|
data.value = res
|
|
helpers.delayHideLoading()
|
|
}).catch(() => {})
|
|
}
|
|
|
|
//获取价格描述文案
|
|
const getPriceDescText = () => {
|
|
let orderInfo = data.value
|
|
if (orderInfo.order_info.receive_type === 2) {
|
|
return '服务价格'
|
|
}
|
|
|
|
if (orderInfo.status === 60) {
|
|
let tailText = orderInfo.total > 0 ? '线下收款¥' + orderInfo.total : '线上收款¥' + orderInfo.online_total
|
|
return `服务价格(订金¥${orderInfo.order_info.online_amount}+${tailText})`
|
|
}
|
|
|
|
return `服务价格(已收订金¥${orderInfo.order_info.online_amount})`
|
|
}
|
|
|
|
//获取订单状态文本
|
|
const getOrderStatusText = (status) => {
|
|
return enums.WORKBENCH_STATUS_TEXT[status]
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.ctr {
|
|
padding: 0 32rpx;
|
|
box-sizing: border-box;
|
|
height: 100vh;
|
|
.price-ctr {
|
|
min-height: 200rpx;
|
|
width: 100%;
|
|
padding: 32rpx 20rpx;
|
|
box-sizing: border-box;
|
|
.price {
|
|
width: 100%;
|
|
height: 80rpx;
|
|
font-weight: 500;
|
|
font-size: 36rpx;
|
|
color: var(--titleColor);
|
|
}
|
|
.desc {
|
|
width: 100%;
|
|
min-height: 56rpx;
|
|
font-size: 34rpx;
|
|
color: var(--summaryColor);
|
|
}
|
|
}
|
|
.info {
|
|
width: 100%;
|
|
background: var(--containerBgColor);
|
|
border-radius: 16rpx;
|
|
padding: 20rpx;
|
|
box-sizing: border-box;
|
|
margin-bottom: 32rpx;
|
|
.item-row {
|
|
width: 100%;
|
|
height: 80rpx;
|
|
position: relative;
|
|
.title {
|
|
width: 200rpx;
|
|
height: 100%;
|
|
font-size: 30rpx;
|
|
color: var(--summaryColor);
|
|
}
|
|
.value {
|
|
width: 446rpx;
|
|
height: 100%;
|
|
font-size: 30rpx;
|
|
color: var(--titleColor);
|
|
.icon {
|
|
margin-left: 4rpx;
|
|
}
|
|
}
|
|
.order-status {
|
|
color: #E18F00 !important;
|
|
}
|
|
.value-theme {
|
|
color: var(--themeColor) !important;
|
|
}
|
|
}
|
|
.item-multi-line {
|
|
width: 100%;
|
|
position: relative;
|
|
padding-bottom: 8rpx;
|
|
box-sizing: border-box;
|
|
.title {
|
|
width: 100%;
|
|
height: 80rpx;
|
|
font-size: 30rpx;
|
|
color: var(--summaryColor);
|
|
.description {
|
|
margin-left: 8rpx;
|
|
height: 80rpx;
|
|
font-size: 30rpx;
|
|
color: var(--descriptionColor);
|
|
font-weight: 400;
|
|
}
|
|
}
|
|
.value {
|
|
width: 100%;
|
|
font-size: 30rpx;
|
|
color: var(--titleColor);
|
|
line-height: 48rpx;
|
|
}
|
|
}
|
|
.report-order-exception {
|
|
width: 100%;
|
|
height: 80rpx;
|
|
margin-top: 20rpx;
|
|
.report-ctr {
|
|
width: 198rpx;
|
|
height: 64rpx;
|
|
border-radius: 8rpx;
|
|
.text {
|
|
font-size: 28rpx;
|
|
color: var(--importantColor);
|
|
}
|
|
}
|
|
}
|
|
.images {
|
|
width: 100%;
|
|
position: relative;
|
|
.title {
|
|
width: 100%;
|
|
height: 80rpx;
|
|
font-size: 30rpx;
|
|
color: var(--summaryColor);
|
|
}
|
|
.imgs-ctr {
|
|
width: 100%;
|
|
min-height: 100rpx;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
.img-ctr {
|
|
width: 120rpx;
|
|
height: 120rpx;
|
|
margin-right: 36rpx;
|
|
margin-top: 16rpx;
|
|
margin-bottom: 16rpx;
|
|
.img {
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 8rpx;
|
|
}
|
|
}
|
|
.up-ctr {
|
|
width: 100rpx;
|
|
height: 100rpx;
|
|
background: var(--contentBgColor);
|
|
border-radius: 8rpx;
|
|
margin-top: 16rpx;
|
|
margin-bottom: 16rpx;
|
|
.up {
|
|
width: 100%;
|
|
height: 36rpx;
|
|
font-size: 20rpx;
|
|
color: var(--summaryColor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.bottom {
|
|
width: 100%;
|
|
padding-top: 20rpx;
|
|
padding-bottom: 68rpx;
|
|
background: var(--pageBgColor);
|
|
box-sizing: border-box;
|
|
position: fixed;
|
|
bottom: 0;
|
|
}
|
|
}
|
|
</style>
|