566 lines
16 KiB
Vue
566 lines
16 KiB
Vue
<template>
|
||
<view class="li-message-page">
|
||
<!-- 自定义导航栏 -->
|
||
<wd-navbar :bordered="false"
|
||
custom-style="background: transparent !important; backdrop-filter: blur(10px) !important; -webkit-backdrop-filter: blur(10px) !important;"
|
||
safeAreaInsetTop fixed placeholder>
|
||
<template #left>
|
||
<view class="li-ml-15 li-mt-10 li-flex li-items-center">
|
||
<text v-if="hasMultiplePages" class="ri-arrow-left-s-line li-text-70"
|
||
@click="toPages({type:'nav'})"></text>
|
||
<text v-if="!hasMultiplePages" class="ri-home-5-line li-text-55 li-mb-8 li-mr-10"
|
||
@click="toPages({type:'home'})"></text>
|
||
<text class="li-text-42">工单详情</text>
|
||
</view>
|
||
</template>
|
||
</wd-navbar>
|
||
<!-- 导航栏背景 -->
|
||
<view class="nav-bg-layer"></view>
|
||
<!-- card -->
|
||
<view class="bg-#FFFFFF li-w-92% li-mx-auto li-rd-20 li-task-card li-pb-25 overflow-hidden li-mt-40">
|
||
<view class="li-flex li-items-start li-justify-between bg-#f9f9f9">
|
||
<view class="li-mb-20">
|
||
<view class="li-flex li-items-center li-text-#5f5f5f li-pl-20 li-pt-20 li-text-28 li-mb-12">
|
||
<text class="ri-file-list-line li-mr-3"></text>
|
||
<text>{{ticketInfo?.ticket_no}}</text>
|
||
<text class="ri-file-copy-line li-text-#009aff li-ml-15" @click="copyTicketNo"></text>
|
||
</view>
|
||
<text class="li-pl-20 li-text-28 li-text-#5f5f5f">创建时间: {{ticketInfo?.create_time}}</text>
|
||
</view>
|
||
<view v-if="ticketInfo?.status !== undefined" class="status-tag li-text-28 li-px-40 li-py-6"
|
||
:class="['status-' + ticketInfo.status]">
|
||
{{getStatusText(ticketInfo.status)}}
|
||
</view>
|
||
</view>
|
||
<view class="li-flex li-items-start li-pt-20 li-pl-20">
|
||
<text v-if="ticketInfo?.status !== undefined" :class="getStatusIcon(ticketInfo.status)"
|
||
class="li-mr-12 li-text-40 li-pt-2"></text>
|
||
<view class="li-flex li-flex-col">
|
||
<text
|
||
class="li-text-32">{{ticketInfo?.status !== undefined ? getStatusText(ticketInfo.status) : ''}}</text>
|
||
<text
|
||
class="li-text-28 li-text-#666">{{ticketInfo?.status !== undefined ? getStatusDescription(ticketInfo.status) : ''}}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- card -->
|
||
<view class="bg-#FFFFFF li-w-92% li-mx-auto li-mt-20 li-rd-20 li-task-card li-pb-30 overflow-hidden">
|
||
<view class="li-pl-30 li-pt-30">业主信息</view>
|
||
<view class="li-pl-30 li-pr-30 li-mt-30">
|
||
<view class="li-flex li-items-center li-justify-between li-text-28">
|
||
<text class="li-w-150 li-text-#9a9a9a">业主姓名</text>
|
||
<text class="li-w-400 li-single-line li-text-right">{{ticketInfo?.order?.name}}</text>
|
||
</view>
|
||
<view class="li-flex li-items-center li-justify-between li-mt-30 li-text-28">
|
||
<text class="li-w-150 li-text-#9a9a9a">联系方式</text>
|
||
<view class="li-flex li-items-center li-w-400 li-single-line justify-between">
|
||
<!-- 左侧留空 -->
|
||
<view></view>
|
||
<!-- 右侧内容 -->
|
||
<view @click="callNumber" class="li-flex li-items-center">
|
||
<text class="ri-phone-line li-text-#009aff li-mr-6"></text>
|
||
<text>{{ticketInfo?.order?.mobile}}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="li-flex li-items-start li-justify-between li-mt-30 li-text-28">
|
||
<text v-if="ticketInfo?.type =='F4' || ticketInfo?.type =='F2'"
|
||
class="li-w-150 li-text-#9a9a9a">上门地址</text>
|
||
<text v-if="ticketInfo?.type =='F6'" class="li-w-150 li-text-#9a9a9a">报修地址</text>
|
||
<text
|
||
class="li-w-400 li-two-line li-text-right">{{ticketInfo?.order?.village_name}}{{ticketInfo?.order?.region_name}}{{ticketInfo?.order?.cell_name}}{{ticketInfo?.order?.house_name}}</text>
|
||
</view>
|
||
<view v-if="ticketInfo?.type =='F2'"
|
||
class="li-flex li-items-start li-justify-between li-mt-30 li-text-28">
|
||
<text class="li-w-150 li-text-#9a9a9a">商品备注</text>
|
||
<text class="li-w-400 li-two-line li-text-right">{{ticketInfo?.order?.address}}</text>
|
||
</view>
|
||
<view v-if="ticketInfo?.type =='F4'"
|
||
class="li-flex li-items-start li-justify-between li-mt-30 li-text-28">
|
||
<text class="li-w-150 li-text-#9a9a9a">预约时间</text>
|
||
<text class="li-w-400 li-two-line li-text-right">{{ticketInfo?.order?.appoint_date}}
|
||
{{ticketInfo?.order?.appoint_time}}</text>
|
||
</view>
|
||
<view v-if="ticketInfo?.type =='F4'"
|
||
class="li-flex li-items-start li-justify-between li-mt-30 li-text-28">
|
||
<text class="li-w-150 li-text-#9a9a9a">建筑面积</text>
|
||
<text class="li-w-400 li-two-line li-text-right">{{ticketInfo?.order?.building_area}}</text>
|
||
</view>
|
||
<view v-if="ticketInfo?.type =='F4'"
|
||
class="li-flex li-items-start li-justify-between li-mt-30 li-text-28">
|
||
<text class="li-w-150 li-text-#9a9a9a">订单状态</text>
|
||
<view class="li-w-400 li-text-right">
|
||
<text :class="['info-tag', 'status-' + ticketInfo?.order?.status]">
|
||
{{getOrderStatusText(ticketInfo?.order?.status)}}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="ticketInfo?.order?.remark"
|
||
class="li-flex li-items-start li-justify-between li-mt-30 li-text-28">
|
||
<text class="li-w-150 li-text-#9a9a9a">工单备注</text>
|
||
<text class="li-w-400 li-two-line li-text-right">{{ticketInfo?.order?.remark}}</text>
|
||
</view>
|
||
|
||
<view v-if="ticketInfo.type == 'F6'"
|
||
class="li-flex li-items-start li-justify-between li-mt-30 li-text-28">
|
||
<text class="li-w-150 li-text-#9a9a9a">报修内容</text>
|
||
<text class="li-w-400 li-two-line li-text-right">{{ticketInfo?.order?.content}}</text>
|
||
</view>
|
||
|
||
<view class="li-flex li-items-start li-justify-between li-mt-30 li-text-28">
|
||
<text class="li-w-150 li-text-#9a9a9a">工单类型</text>
|
||
<view class="li-w-400 li-text-right">
|
||
<text v-if="ticketInfo?.type === 'F2'" class="info-tag type-delivery">商品</text>
|
||
<text v-if="ticketInfo?.type === 'F4'" class="info-tag type-measure">量房</text>
|
||
<text v-if="ticketInfo?.type === 'F6'" class="info-tag type-repair">维修</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="(ticketInfo?.type =='F4' || ticketInfo?.type =='F6') && ticketInfo.order.images"
|
||
class="li-flex li-items-start li-justify-between li-mt-30 li-text-28">
|
||
<text class="li-w-150 li-text-#9a9a9a">附件上传</text>
|
||
<view class="li-flex li-flex-col li-w-400 justify-end">
|
||
<view class="li-flex justify-between li-items-center li-mt-20">
|
||
<!-- 左侧留空 -->
|
||
<view></view>
|
||
<!-- 右侧内容 -->
|
||
<view class="li-flex li-items-center li-flex-wrap">
|
||
<image
|
||
v-for="(item, index) in ticketInfo.order.images.split(',')"
|
||
:key="index"
|
||
class="li-w-110 li-h-110 li-rd-10 li-mr-10 li-mb-10"
|
||
:src="item"
|
||
mode="aspectFill"
|
||
@click="previewImage(item)">
|
||
</image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="ticketInfo?.type =='F2' && ticketInfo?.product?.length>0"
|
||
class="li-flex li-items-start li-justify-between li-mt-30 li-text-28">
|
||
<text class="li-w-150 li-text-#9a9a9a">商品信息</text>
|
||
<view class="li-w-400 li-flex li-flex-col">
|
||
<!-- 商品列表 -->
|
||
<view v-for="(item, index) in ticketInfo.product" :key="index" class="li-product-item li-mb-20">
|
||
<view class="li-flex li-items-center">
|
||
<!-- 商品图片 -->
|
||
<image class="li-product-image" :src="item.picture" mode="aspectFill"
|
||
@click="previewImage(item.picture)">
|
||
</image>
|
||
<!-- 商品信息 -->
|
||
<view class="li-product-info">
|
||
<text class="li-product-name">{{item.product_name}}</text>
|
||
<text class="li-product-spec">{{item.spec_name || ''}}</text>
|
||
<view class="li-qty">×{{item.num}}</view>
|
||
</view>
|
||
</view>
|
||
<!-- 分隔线 -->
|
||
<view v-if="index < ticketInfo.product.length - 1" class="li-divider"></view>
|
||
</view>
|
||
|
||
<!-- 商品总计 -->
|
||
<view v-if="ticketInfo.product.length > 1" class="li-product-count">
|
||
共 {{ticketInfo.product.length}} 件商品
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
</view>
|
||
</view>
|
||
<view class="li-w-85% li-mx-auto li-mt-90">
|
||
<wd-button @click="sumbit" :loading="bntloading" block custom-class="custom-shadow"> 接单</wd-button>
|
||
</view>
|
||
|
||
<wd-toast />
|
||
<zero-loading type="wobble" v-if="loading"></zero-loading>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref } from 'vue'
|
||
import { onLoad } from '@dcloudio/uni-app'
|
||
import { useNavigation } from '@/hooks/useNavigation'
|
||
import { ticketPoolInfo, ticketAccept } from '@/api/ticket'
|
||
import { useToast } from '@/uni_modules/wot-design-uni'
|
||
import { throttle } from '@/utils/common'
|
||
|
||
const Toast = useToast()
|
||
const loading = ref<boolean>(false)
|
||
const bntloading = ref<boolean>(false)
|
||
|
||
const ticketInfo = ref<any>({
|
||
ticket_no: '',
|
||
create_time: '',
|
||
status: undefined,
|
||
type: '',
|
||
order: {
|
||
name: '',
|
||
mobile: '',
|
||
region_name: '',
|
||
cell_name: '',
|
||
house_name: '',
|
||
address: '',
|
||
appoint_date: '',
|
||
appoint_time: '',
|
||
building_area: '',
|
||
status: 0,
|
||
images: '',
|
||
remark: ''
|
||
}
|
||
})
|
||
|
||
// 使用导航 composable
|
||
const {
|
||
hasMultiplePages,
|
||
isTabBarPage,
|
||
checkRouteStack
|
||
} = useNavigation()
|
||
|
||
onLoad((q) => {
|
||
checkRouteStack()
|
||
if (q.ticket_id) {
|
||
loadInfo(q.ticket_id)
|
||
}
|
||
})
|
||
|
||
const loadInfo = async (ticket_id : string) => {
|
||
try {
|
||
loading.value = true
|
||
const res = await ticketPoolInfo({ ticket_id })
|
||
if (res.data) {
|
||
ticketInfo.value = {
|
||
...ticketInfo.value,
|
||
...res.data
|
||
}
|
||
}
|
||
} catch (error) {
|
||
Toast.error('加载失败,请重试')
|
||
console.error('加载工单信息失败:', error)
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 复制工单号
|
||
const copyTicketNo = () => {
|
||
if (!ticketInfo.value?.ticket_no) return
|
||
uni.setClipboardData({
|
||
data: ticketInfo.value.ticket_no,
|
||
showToast: false,
|
||
success: () => {
|
||
Toast.success('工单号已复制')
|
||
}
|
||
})
|
||
}
|
||
|
||
const callNumber = () => {
|
||
// uni.makePhoneCall({
|
||
// phoneNumber: ticketInfo.value.order.mobile
|
||
// });
|
||
|
||
}
|
||
|
||
const sumbit = throttle(async () => {
|
||
bntloading.value = true
|
||
var res = await ticketAccept({ ticket_id: ticketInfo.value.ticket_id })
|
||
bntloading.value = false
|
||
if (res.code == 200) {
|
||
Toast.success('已接单')
|
||
setTimeout(() => {
|
||
uni.navigateBack({
|
||
delta: 1
|
||
})
|
||
}, 500)
|
||
}
|
||
|
||
}, 500)
|
||
|
||
const toPages = (item : any) => {
|
||
switch (item.type) {
|
||
case 'nav':
|
||
uni.navigateBack({
|
||
delta: 1
|
||
});
|
||
break;
|
||
case 'home':
|
||
uni.switchTab({
|
||
url: '/pages/index/index'
|
||
})
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
// 状态配置
|
||
const statusConfig = {
|
||
0: {
|
||
color: '#1890ff',
|
||
bgColor: '#f0f9ff',
|
||
icon: 'ri-time-line',
|
||
text: '待接单',
|
||
description: '工单待处理,点击按钮确认接单'
|
||
},
|
||
1: {
|
||
color: '#1890ff',
|
||
bgColor: '#f0f9ff',
|
||
icon: 'ri-truck-line',
|
||
text: '已派单',
|
||
description: '工单已分配,请及时处理'
|
||
},
|
||
2: {
|
||
color: '#52c41a',
|
||
bgColor: '#f0fff5',
|
||
icon: 'ri-checkbox-circle-line',
|
||
text: '已完成',
|
||
description: '工单已完成处理'
|
||
},
|
||
3: {
|
||
color: '#8c8c8c',
|
||
bgColor: '#f5f5f5',
|
||
icon: 'ri-close-circle-line',
|
||
text: '已取消',
|
||
description: '工单已取消'
|
||
}
|
||
}
|
||
|
||
// 订单状态配置
|
||
const orderStatusConfig = {
|
||
0: { text: '已提交', color: '#ff9d00', bgColor: '#fff7e6' },
|
||
1: { text: '已完成', color: '#52c41a', bgColor: '#f6ffed' },
|
||
2: { text: '已取消', color: '#8c8c8c', bgColor: '#fafafa' }
|
||
}
|
||
|
||
// 工单类型配置
|
||
const typeConfig = {
|
||
F2: { text: '配送', color: '#1890ff', bgColor: '#f0f7ff' },
|
||
F4: { text: '量房', color: '#722ed1', bgColor: '#f9f0ff' },
|
||
F6: { text: '维修', color: '#13c2c2', bgColor: '#f0fafa' }
|
||
}
|
||
|
||
// 获取状态颜色
|
||
const getStatusColor = (status : number) => {
|
||
return statusConfig[status]?.color || '#666666'
|
||
}
|
||
|
||
// 获取状态背景色
|
||
const getStatusBgColor = (status : number) => {
|
||
return statusConfig[status]?.bgColor || '#f5f5f5'
|
||
}
|
||
|
||
// 获取状态文字
|
||
const getStatusText = (status : number) => {
|
||
return statusConfig[status]?.text || '未知状态'
|
||
}
|
||
|
||
// 获取状态图标
|
||
const getStatusIcon = (status : number) => {
|
||
return `${statusConfig[status]?.icon} li-text-${getStatusColor(status).substring(1)}`
|
||
}
|
||
|
||
// 获取状态描述
|
||
const getStatusDescription = (status : number) => {
|
||
return statusConfig[status]?.description || '状态未知'
|
||
}
|
||
|
||
// 获取订单状态文字
|
||
const getOrderStatusText = (status : number) => {
|
||
return orderStatusConfig[status]?.text || '未知状态'
|
||
}
|
||
|
||
// 预览商品图片
|
||
const previewImage = (image) => {
|
||
if (!image) return
|
||
uni.previewImage({
|
||
urls: [image],
|
||
current: image
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.li-message-page {
|
||
width: 100%;
|
||
min-height: 100vh;
|
||
background: linear-gradient(to bottom,
|
||
rgba(217, 237, 255, 0.9) 0%,
|
||
rgba(217, 237, 255, 0.9) 20%,
|
||
rgba(207, 207, 207, 0.2) 40%,
|
||
rgba(207, 207, 207, 0.2) 60%,
|
||
rgba(207, 207, 207, 0.2) 80%,
|
||
rgba(207, 207, 207, 0.2) 100%);
|
||
background-attachment: fixed;
|
||
|
||
}
|
||
|
||
|
||
// 导航栏背景层
|
||
.nav-bg-layer {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: var(--window-top);
|
||
background: linear-gradient(to bottom,
|
||
rgba(217, 237, 255, 0.95),
|
||
rgba(217, 237, 255, 0.85));
|
||
backdrop-filter: blur(10px);
|
||
-webkit-backdrop-filter: blur(10px);
|
||
z-index: 998;
|
||
}
|
||
|
||
.li-task-card {
|
||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.status-tag {
|
||
border-radius: 0 0 0 25rpx;
|
||
|
||
&.status-0 {
|
||
color: #1890ff;
|
||
background-color: #f0f9ff;
|
||
}
|
||
|
||
&.status-1 {
|
||
color: #1890ff;
|
||
background-color: #f0f9ff;
|
||
}
|
||
|
||
&.status-2 {
|
||
color: #52c41a;
|
||
background-color: #f0fff5;
|
||
}
|
||
|
||
&.status-3 {
|
||
color: #8c8c8c;
|
||
background-color: #f5f5f5;
|
||
}
|
||
}
|
||
|
||
.info-tag {
|
||
display: inline-block;
|
||
padding: 4rpx 16rpx;
|
||
font-size: 24rpx;
|
||
border-radius: 4rpx;
|
||
|
||
&.type-delivery {
|
||
color: #1890ff;
|
||
background-color: #f0f7ff;
|
||
border: 1px solid #e6f4ff;
|
||
}
|
||
|
||
&.type-measure {
|
||
color: #722ed1;
|
||
background-color: #f9f0ff;
|
||
border: 1px solid #f4e6ff;
|
||
}
|
||
|
||
&.type-repair {
|
||
color: #13c2c2;
|
||
background-color: #f0fafa;
|
||
border: 1px solid #e6f7f7;
|
||
}
|
||
|
||
&.status-0 {
|
||
color: #ff9d00;
|
||
background-color: #fff7e6;
|
||
border: 1px solid #ffedc7;
|
||
}
|
||
|
||
&.status-1 {
|
||
color: #52c41a;
|
||
background-color: #f6ffed;
|
||
border: 1px solid #e8ffd1;
|
||
}
|
||
|
||
&.status-2 {
|
||
color: #8c8c8c;
|
||
background-color: #fafafa;
|
||
border: 1px solid #f0f0f0;
|
||
}
|
||
}
|
||
|
||
::v-deep .wd-button {
|
||
width: 160rpx !important;
|
||
height: 65rpx !important;
|
||
min-width: 160rpx !important;
|
||
}
|
||
|
||
.custom-shadow {
|
||
height: 85rpx !important;
|
||
font-size: 32rpx !important;
|
||
box-shadow: 0 3px 1px -2px rgb(0 0 0 / 20%), 0 2px 2px 0 rgb(0 0 0 / 14%), 0 1px 5px 0 rgb(0 0 0 / 12%);
|
||
background-color: #2EA1EA !important;
|
||
width: 100% !important;
|
||
display: flex !important;
|
||
align-items: center !important;
|
||
justify-content: center !important;
|
||
}
|
||
|
||
// 商品项样式
|
||
.li-product-item {
|
||
position: relative;
|
||
padding-bottom: 15rpx;
|
||
|
||
.li-product-image {
|
||
width: 120rpx;
|
||
height: 120rpx;
|
||
flex-shrink: 0;
|
||
border-radius: 10rpx;
|
||
background-color: #f9f9f9;
|
||
border: 1px solid #f5f5f5;
|
||
}
|
||
|
||
.li-product-info {
|
||
flex: 1;
|
||
margin-left: 20rpx;
|
||
overflow: hidden;
|
||
padding-right: 10rpx;
|
||
}
|
||
|
||
.li-product-name {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 1;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.li-product-spec {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
margin-top: 8rpx;
|
||
display: block;
|
||
}
|
||
|
||
.li-qty {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
margin-top: 10rpx;
|
||
}
|
||
|
||
.li-divider {
|
||
height: 1px;
|
||
background-color: #f5f5f5;
|
||
margin-top: 15rpx;
|
||
width: 100%;
|
||
}
|
||
}
|
||
|
||
.li-product-count {
|
||
font-size: 26rpx;
|
||
color: #999;
|
||
text-align: right;
|
||
margin-top: 10rpx;
|
||
padding-top: 15rpx;
|
||
border-top: 1px solid #f0f0f0;
|
||
}
|
||
</style> |