wanyu_frontend/pages/order/order-info.vue
2025-04-24 09:34:48 +08:00

464 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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">
<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 class="value flex-r value-theme" @click="helpers.makePhoneCall(data.order_info.tel)">
<me-icon class="icon" type="icon-call" color="var(--themeColor)" size="40rpx"></me-icon>
<text>{{ data.order_info.tel }}</text>
</view>
</view>
</template>
<view class="item-row flex-sb line-after">
<view class="title flex-l">预约上门时间</view>
<view 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">
<view class="title flex-l">详情</view>
<view class="value flex-l">{{data.order_info.detail ? data.order_info.detail : '暂无详情'}}</view>
</view>
<view class="item-multi-line">
<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_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" 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="previewImage(imgUrl)" v-for="(imgUrl, index) in data.arrive_images" :key="index" class="img-ctr" :style="{marginRight: (index+1) % 5 === 0 ? '0' : '36rpx'}">
<image class="img" mode="aspectFill" :src="imgUrl"></image>
</view>
</view>
</view>
</view>
<!-- 已完成 -->
<view class="info" v-if="data.status === enums.ORDER_DISPATCH_STATUS.STATUS_FINISH">
<view class="images line-after">
<view class="title flex-l">完成图片</view>
<view class="imgs-ctr">
<view @click="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="aspectFill" :src="imgUrl"></image>
</view>
</view>
</view>
<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="previewImage(data.image)" :key="index" class="img-ctr">
<image class="img" mode="aspectFill" :src="data.image"></image>
</view>
</view>
</view>
</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="rejectOrder()" active-color="var(--contentBgColor)" text="拒 绝" width="686rpx" text-color="var(--titleColor)"></me-button>
<me-button @click="acceptOrder()" text="确认接单" width="686rpx" icon-type="icon-flashlight" margin-top="32rpx"></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="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 canReportOrderException = computed(() => {
return data.value.status !== enums.ORDER_DISPATCH_STATUS.STATUS_TOGET && data.value.status !== enums.ORDER_DISPATCH_STATUS.STATUS_REFUSED
})
//更新师傅备注
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)) {
return helpers.showToast(`上门失败!距离客户地址超过 500米当前距离${distances.distance}${distances.unit}`)
}
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]
}
//预览图片
const previewImage = (url) => {
uni.previewImage({
urls: [url],
longPressActions: {
itemList: ['发送给朋友', '保存图片', '收藏'],
success: function(data) {
},
fail: function(err) {
console.log(err.errMsg);
}
}
});
}
</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: 28rpx;
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-right: 8rpx;
}
}
.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;
.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: 100rpx;
height: 100rpx;
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>