fuyuan-housekeeping-admin/src/views/order/lists/detail.vue

578 lines
24 KiB
Vue
Raw Blame History

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>
<!-- Header Start -->
<el-card class="!border-none mt-4" shadow="never">
<el-page-header content="订单详情" @back="$router.back()" />
</el-card>
<!-- Header End -->
<div class="order-detail-main">
<!-- 订单信息 Start -->
<el-card class="!border-none mt-4" shadow="never" style="padding: 0 20px">
<template #header>
<div class="card-header">
<span class="font-medium nr">订单信息</span>
</div>
</template>
<!-- 订单信息 -->
<el-form :inline="true" :model="formData" label-width="auto" class="order-form">
<el-form-item label="订单状态: ">
<div class="content text-warning">{{ formData.orderStatusName || '-' }}</div>
</el-form-item>
<!-- <el-form-item label="支付状态: ">
<div class="content">{{ formData.payStatusName || '-' }}</div>
</el-form-item> -->
<el-form-item label="订单编号: ">
<div class="content">{{ formData.sn || '-' }}</div>
</el-form-item>
<!-- <el-form-item label="支付方式: ">
<div class="content">{{ formData.payWayName || '-' }}</div>
</el-form-item> -->
<el-form-item label="下单时间: ">
<div class="content">{{ formData.createTime || '-' }}</div>
</el-form-item>
<!-- <el-form-item label="支付时间: ">
<div class="content">{{ formData.payTime || '-' }}</div>
</el-form-item> -->
<el-form-item label="用户昵称: ">
<div class="content">{{ formData.nickname || '-' }}</div>
</el-form-item>
<el-form-item label="用户备注: ">
<div class="content">{{ formData.userRemark || '-' }}</div>
</el-form-item>
<el-form-item label="核销码: ">
<div class="content">{{ formData.verificationCode || '-' }}</div>
</el-form-item>
<el-form-item label="核销状态: ">
<div class="content">
<span class="warning" v-if="formData.verificationStatusName">
{{ formData.verificationStatusName }}
</span>
<span v-else>-</span>
</div>
</el-form-item>
<el-form-item label="完成时间: ">
<div class="content break-words">{{ formData.finishTime || '-' }}</div>
</el-form-item>
<el-form-item label="商家备注: ">
<div class="w-[300px] break-words">{{ formData.orderRemarks! || '-' }}</div>
</el-form-item>
<el-form-item label="退款原因: " v-if="formData.orderStatus == 4">
<div class="content">
{{ formData?.orderRefundDetailVo?.refundReason || '-' }}
</div>
</el-form-item>
</el-form>
<!-- Button Group Start -->
<div class="button-group">
<operation
btnStyle="primary"
:id="id"
:cancelBtn="formData.cancelBtn"
:verificationBtn="formData.verificationBtn"
:verificationStatus="formData.verificationStatus"
:verificationCode="formData.verificationCode"
:orderRemarks="formData.orderRemarks"
:confirmServiceBtn="formData.isDispatch === 1 && formData.orderStatus === 1"
@refresh="getOrderDetail"
@cancelOrder="() => handleCancelOrder(formData, getOrderDetail)"
/>
</div>
<!-- Button Group End -->
</el-card>
<!-- 订单信息 End -->
<!-- 退款信息 -->
<el-card v-if="isShowOrderRefundDetailVo()" class="!border-none mt-4" shadow="never" style="padding: 0 20px">
<template #header>
<div class="card-header">
<span class="font-medium nr">退款信息</span>
</div>
</template>
<div>
<el-form :inline="true" :model="formData" class="flex flex-col">
<el-form-item label="申请退单时间: ">
<div class="content !w-full">
{{ orderRefundDetailVo.refundTime }}
<span v-if="orderRefundDetailVo.serviceTimeBeforeMinute">
,距离上门服务时间
<span class="text-error">{{ orderRefundDetailVo.serviceTimeBeforeMinute }}</span>
分钟 ,应扣款
<span class="text-error">{{ orderRefundDetailVo.deductionRatio }}%</span>
<span class="text-error">{{ orderRefundDetailVo.deductionMoney }}元。</span>
<div>
实际扣款
<span class="text-error">{{ orderRefundDetailVo.practicalDeductionRatio }} %</span>
<span class="text-error">{{ orderRefundDetailVo.practicalDeductionMoney }} 元</span>
</div>
</span>
</div>
</el-form-item>
<el-form-item label="退款原因: ">
{{ parseEmpty(orderRefundDetailVo, 'refundReason') }}
</el-form-item>
</el-form>
</div>
</el-card>
<!-- 服务师傅 Start -->
<el-card class="!border-none mt-4" shadow="never" style="padding: 0 20px" v-if="formData.orderStatus !== 0">
<template #header>
<span class="font-medium nr">服务师傅</span>
</template>
<el-form :inline="true" :model="formData" label-width="auto">
<el-form-item label="服务师傅">
<div v-if="formData.orderStatus == 1">
<div v-if="!formData.staffId && btnStatus == 0">
<el-button type="primary" @click="handleDispatch">指派师傅</el-button>
</div>
<div v-if="btnStatus == 1" class="flex items-center">
<el-cascader :options="options" :props="props2" @change="handleSelect" v-model="areaValue" />
<el-select v-model="selStaff" class="mx-2" value-key="id" @change="handleChange">
<el-option v-for="item in staffData" :key="item.id" :label="item.name" :value="item">
<div class="flex items-center">
<el-image style="width: 30px; height: 30px; border-radius: 50%" :src="item.avatarUrl" :fit="'cover'" />
<div class="ml-2">
{{ `${item.name}${item.sn}` }}
</div>
</div>
</el-option>
</el-select>
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleConfirm">确认指派</el-button>
</div>
<div v-if="btnStatus == 2" class="flex items-center">
<div class="flex items-center">
<el-image style="width: 44px; height: 44px; border-radius: 50%" :src="formData.staffImage" :fit="'cover'" />
<div class="ml-2">
{{ `${formData.staffName}${formData.staffSn}` }}
</div>
</div>
<el-button type="primary" @click="handleReDispatch">重新指派</el-button>
</div>
</div>
<div v-if="formData.staffId && formData.orderStatus !== 1" class="flex items-center">
<div class="flex items-center">
<el-image style="width: 44px; height: 44px; border-radius: 50%" :src="formData.staffImage" :fit="'cover'"></el-image>
<div class="ml-2">
{{ `${formData.staffName}${formData.staffSn}` }}
</div>
</div>
</div>
</el-form-item>
</el-form>
</el-card>
<!-- 服务师傅 End -->
<!-- 历史服务师傅 -->
<el-card
class="!border-none mt-4"
shadow="never"
style="padding: 0 20px"
v-if="formData.staffReassignmentListVos && formData.staffReassignmentListVos.length > 0"
>
<template #header>
<span class="font-medium nr">历史服务师傅</span>
</template>
<div v-for="(staff, index) in formData.staffReassignmentListVos" class="mb-2" :key="index">
<div class="flex items-center">
<el-image style="width: 44px; height: 44px; border-radius: 50%" :src="staff.avatar" :fit="'cover'"></el-image>
<div class="ml-2">
{{ `${staff.staffName}${staff.staffSn}` }}
</div>
<!-- <div>
上门服务时间{{ staff.timeBefore < 0 ? '后' : '前' }}{{ staff.timeBefore.toString().replace(/\-/g, ' ') }}分钟退单
<span style="color: #f56c6c">{{ staff.deductScore }}</span>
(改派时间{{ staff.createTime }})
</div> -->
<div>
上门服务时间{{ staff.timeBefore < 0 ? '后' : '前'
}}{{ staff.timeBefore.toString().replace(/\-/g, ' ') }}分钟退单改派时间{{ staff.createTime }}
</div>
</div>
</div>
</el-card>
<!-- 预约信息 Start -->
<el-card class="!border-none mt-4" shadow="never" style="padding: 0 20px">
<template #header>
<span class="font-medium nr">预约信息</span>
</template>
<!-- 预约信息 -->
<el-form :inline="true" :model="formData" label-width="auto">
<el-form-item label="预约时间: ">
<div class="content">
{{ formData.appointTime }} {{ formData.weekDay }} {{ formData.appointTimeStartStr }}-{{ formData.appointTimeEndStr }}
</div>
</el-form-item>
<el-form-item label="联系人: ">
<div class="content">{{ formData.contact || '-' }}</div>
</el-form-item>
<el-form-item label="手机号码: ">
<div class="content">{{ formData.mobile || '-' }}</div>
</el-form-item>
<el-form-item label="预约地址: ">
<div class="content">
{{ formData.province + formData.city + formData.district + formData.address || '-' }}
</div>
</el-form-item>
</el-form>
</el-card>
<!-- 预约信息 End -->
<!-- 服务信息 Start -->
<el-card class="!border-none mt-4" shadow="never" style="padding: 0 20px">
<template #header>
<span class="font-medium nr">服务信息</span>
</template>
<!-- 服务信息 -->
<el-table ref="tableDataRef" :data="goodsData" style="width: 100%">
<el-table-column label="服务名称">
<template #default="scope">
<div class="flex items-center">
<el-image style="width: 58px; height: 58px" :src="scope.row.goodsImage" :fit="'cover'"></el-image>
<div class="justify-center ml-2 flex-1">{{ scope.row.goodsName }}</div>
</div>
</template>
</el-table-column>
<el-table-column property="goodsPrice" label="价格" width="120">
<template #default="scope">¥{{ parsePrice(scope.row) }}</template>
</el-table-column>
<el-table-column property="unitName" label="单位" width="120" />
<el-table-column property="goodsNum" label="数量" width="120" />
<el-table-column property="totalAmount" label="总价格" width="120" />
<!-- <el-table-column property="goodsNum" label="是否使用优惠券" width="160" fixed="right">
<template #default="{ row }">{{ isUseCoupon(row) }}</template>
</el-table-column> -->
<!-- <el-table-column property="deductionMoney" label="抵扣金额" width="120" fixed="right" /> -->
<!-- <el-table-column property="orderAmount" label="实付金额" width="120" fixed="right" /> -->
</el-table>
</el-card>
<!-- 服务信息 End -->
<!-- 优惠券信息 -->
<!-- <el-card class="!border-none mt-4" shadow="never" style="padding: 0 20px" v-if="formData.couponDetailVo">
<template #header>
<span class="font-medium nr">优惠券信息</span>
</template>
<el-table ref="tableDataRef" :data="couponInfo" style="width: 100%">
<el-table-column property="name" label="优惠券名称" max-width="300" />
<el-table-column property="useGoodsType" label="优惠券类型" max-width="300">
<template #default="{ row }">{{ parseUseGoodsType(row) }}</template>
</el-table-column>
<el-table-column property="money" label="优惠券面值" max-width="300" />
<el-table-column property="sendTime" label="发放时间" max-width="300">
<template #default="{ row }">{{ parseTime(row, 'send') }}</template>
</el-table-column>
<el-table-column property="useTime" label="使用时间" max-width="300">
<template #default="{ row }">{{ parseTime(row, 'use') }}</template>
</el-table-column>
<el-table-column property="getType" label="发放方式" max-width="300">
<template #default="{ row }">{{ parseGetType(row) }}</template>
</el-table-column>
</el-table>
</el-card> -->
<!-- 订单日志 Start -->
<el-card class="!border-none mt-4" shadow="never" style="padding: 0 20px">
<template #header>
<span class="font-medium nr">订单日志</span>
</template>
<!-- 订单日志 -->
<el-table ref="tableDataRef" :data="formData.orderLogList" style="width: 100%">
<el-table-column property="operatorName" label="操作人" max-width="300" />
<el-table-column property="content" label="操作事件" max-width="300" />
<el-table-column property="operateTime" label="操作时间" max-width="300" />
</el-table>
</el-card>
<!-- 订单日志 End -->
</div>
</template>
<script lang="ts" setup>
import { apiDispatchStaff, apiDispatchStaffScore, apiMasterLists, apiOrderDetail } from '@/api/order/lists'
import { PriceEnum, ReceiveOrderEnum, getTypeMap, useGoodsTypeMap } from '@/enums/modeEnum'
import { useCreateModal } from '@/hooks/useCreateModal'
import area from '@/utils/area'
import feedback from '@/utils/feedback'
import { formatString, parseCouponTime, parseEmpty } from '@/utils/util'
import { ref } from 'vue'
import cancelOrderDialog from './components/cancelOrderDialog.vue'
import dispatchDialog from './components/dispatchDialog.vue'
import Operation from './components/operation.vue'
import { useCancelOrderAction } from './hook'
const route = useRoute()
const id = ref<any>(route.query.id)
const formData = ref<any>({})
const staffData = ref<any>([])
const selStaff = ref('') // 当前选中的师傅
const region = ref<any>(null) // 当前选中地区
const btnStatus = ref(0) // 0-显示指派 1-显示确认和取消 2-显示重新指派
const staff = ref<any>({})
const options = ref<any>(area) // 地区列表
const props2 = {
checkStrictly: true
}
const goodsData = ref<any>([
{
goodsId: '',
goodsImage: '',
goodsName: '',
goodsNum: 0,
goodsPrice: '',
unitName: '',
totalPayPrice: '',
deductionMoney: '',
totalAmount: '',
orderAmount: '',
couponDetailVo: {},
priceType: PriceEnum.CUSTOMER_PRICE,
priceRange: ''
}
])
const couponInfo = ref([
{
name: '',
useGoodsType: '',
money: '',
getType: '',
sendTimeStart: '',
sendTimeEnd: '',
useTimeStart: '',
useTimeEnd: '',
channelType: '',
createTime: ''
}
])
const parseUseGoodsType = computed(() => {
return (row: any) => {
const { useGoodsType } = row
return useGoodsTypeMap[useGoodsType]
}
})
const parseGetType = computed(() => {
return (row: any) => {
const { getType } = row
return getTypeMap[getType]
}
})
const parseTime = computed(() => {
return (row: any, type: string) => {
const { sendTimeStart, sendTimeEnd, useTimeStart, useTimeEnd, channelType, getType, createTime } = row
const obj: Record<string, string[]> = {
send: [sendTimeStart, sendTimeEnd],
use: [useTimeStart, useTimeEnd]
}
const [startTime, endTime] = obj[type]
if (getType === 3 && channelType === 2) {
//渠道派发-指定用户
return createTime
} else if (!startTime || !endTime) {
return '--'
}
return `${parseCouponTime(startTime)}${parseCouponTime(endTime)}`
}
})
const isUseCoupon = computed(() => {
return (row: any) => {
const { couponDetailVo } = row
return !couponDetailVo ? '否' : '是'
}
})
const isShowOrderRefundDetailVo = computed(() => {
return () => {
if (Object.keys(unref(formData)).length > 0) {
return unref(formData).orderRefundDetailVo && Object.keys(unref(formData).orderRefundDetailVo).length > 0
} else {
return false
}
}
})
const orderRefundDetailVo = computed(() => (unref(isShowOrderRefundDetailVo) ? unref(formData).orderRefundDetailVo : {}))
/**是否派发给师傅 */
const isDispatch = computed(() => (status: number) => status === ReceiveOrderEnum.PAUSE)
const parsePrice = computed(() => row => {
const { priceType, priceRange, goodsPrice } = row
return priceType == PriceEnum.CUSTOMER_PRICE ? goodsPrice : formatString(priceRange)
})
function generateCouponFields(res: any) {
const fields = {
name: '优惠券名称',
useGoodsType: '优惠券类型',
money: '优惠券面值',
sendTime: '发放时间',
useTime: '使用时间',
getType: '发放方式'
}
if (res.couponDetailVo) {
for (const k in couponInfo.value[0]) {
couponInfo.value[0][k] = res.couponDetailVo[k]
}
}
}
// 获取订单详情
const getOrderDetail = async (val?: string): Promise<void> => {
const res = await apiOrderDetail({ id: id.value })
formData.value = res
for (const k in goodsData.value[0]) {
goodsData.value[0][k] = formData.value[k]
}
if (val === '') formData.value.orderRemarks = val
if (formData.value.staffId && formData.value.orderStatus == 1) {
btnStatus.value = 2
}
generateCouponFields(res)
}
// 记录所选中的数据对象
const handleChange = (val: any) => {
staff.value = val
return val
}
// const areaValue = ref([440000, 440100, 440118])
const areaValue = ref([])
// 选中不同地区的师傅列表
const handleSelect = async (val: number[]) => {
// 记录所选地区
region.value = val[val.length - 1]
const params = {
provinceId: val[0],
cityId: val[1],
districtId: val[2],
isReceiveOrder: ReceiveOrderEnum.ENABLEDING,
isOrder: ReceiveOrderEnum.ENABLEDING,
appointTimeStart: unref(formData).appointTimeStart,
appointTimeEnd: unref(formData).appointTimeEnd,
goodsId: goodsData.value[0].goodsId,
staffId: formData.value.staffId
}
const { lists } = await apiMasterLists({ ...params })
staffData.value = lists
areaValue.value = val
}
watch(
() => formData.value.staffId,
newVal => {
if (newVal) {
const { provinceId, cityId, districtId } = formData.value
areaValue.value = [provinceId, cityId, districtId]
handleSelect(areaValue.value)
}
}
)
// 指派师傅
const handleDispatch = async () => {
getOrderDetail()
btnStatus.value = 1
}
const commandComponent = useCreateModal(dispatchDialog)
// 确认指派
const handleConfirm = async () => {
if (!region.value) {
feedback.msgError('请选择地区')
return
} else if (!selStaff.value) {
feedback.msgError('请选择师傅')
return
}
/**重新指派师傅才有弹框 */
if (unref(formData).isDispatch === 1 && unref(formData).staffId) {
const res = await fetchScore()
if (!Object.keys(res).length) return dispatchStaff()
commandComponent({
title: '重新指派师傅',
width: 500,
state: {
intervalTime: res.intervalTime,
value: res.value
},
onConfirm: async payload => {
const data = {
timeBefore: res.intervalTime,
deductScore: payload.reason
}
dispatchStaff(data)
}
})
} else {
dispatchStaff()
}
}
/**调用指派接口 */
async function dispatchStaff(payload = {}) {
try {
const data = {
id: formData.value.id,
staffId: unref(staff).id
}
Object.assign(data, { ...payload })
await apiDispatchStaff(data)
feedback.msgSuccess('操作成功')
btnStatus.value = 2
selStaff.value = ''
getOrderDetail()
handleSelect(areaValue.value)
} catch (error) {}
}
/**获取分数 */
const fetchScore = async () => {
try {
const data = {
orderId: unref(formData).id,
staffId: unref(formData).staffId
}
return await apiDispatchStaffScore(data)
} catch (error) {}
}
// 重新指派
const handleReDispatch = () => {
btnStatus.value = 1
selStaff.value = ''
}
// 取消指派
const handleCancel = () => {
btnStatus.value = formData.value.staffId ? 2 : 0
selStaff.value = ''
getOrderDetail()
}
const { handleCancelOrder } = useCancelOrderAction(cancelOrderDialog)
onMounted(async () => {
if (id.value) await getOrderDetail()
// handleSelect([440000, 440100, 440118])
})
</script>
<style lang="scss">
.order-detail-main .el-card__header,
.order-detail-main .el-card__body {
padding: calc(var(--el-card-padding) - 2px) 0;
}
.content {
width: 24vw;
}
.button-group {
border-top: 1px solid #f2f2f2;
}
.order-form {
display: grid;
grid-template-columns: repeat(2, 1fr);
}
</style>