<template>
|
|
<view class="timeline-container">
|
|
<!-- 日期和状态标签 -->
|
|
<view class="date-header">
|
|
<view class="date-box">
|
|
<view class="date-box-color" :style="{'background-color': getTopBgColor()}"></view>
|
|
<view class="date-month-day">{{ formatDate(date).month }}-{{ formatDate(date).day }}</view>
|
|
</view>
|
|
<view class="status-tag" :class="{'status-tag-pending': status}">
|
|
|
|
<image src="/static/images/ydd/icon1.png"
|
|
mode="aspectFit"
|
|
v-if="status"
|
|
class="status-icon"></image>
|
|
|
|
<image src="/static/images/order/success.png"
|
|
mode="aspectFit"
|
|
v-else
|
|
class="status-icon"></image>
|
|
|
|
{{ status ? '待上门' : '已完成' }}{{ orderCount }}单
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 空状态显示 -->
|
|
<view v-if="!processedList || processedList.length === 0" class="empty-state">
|
|
<text class="empty-text">暂无订单数据</text>
|
|
</view>
|
|
|
|
<!-- 时间线主体 -->
|
|
<view v-else class="timeline-body" v-for="(item, index) in processedList" :key="index">
|
|
<view class="timeline-line"></view>
|
|
|
|
<view class="time-point">
|
|
<view class="time-icon">
|
|
<image src="/static/images/order/address.png" mode="aspectFit" class="time-image"></image>
|
|
</view>
|
|
<view class="time-text">{{ item.address }}</view>
|
|
<view class="collapse-icon" @click="toggleServiceCard(index)">
|
|
{{ serviceCardCollapsed[index] ? '展开' : '收起' }} <text class="arrow" :class="{'arrow-up': !serviceCardCollapsed[index]}">▼</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 服务内容卡片 -->
|
|
<view v-if="!serviceCardCollapsed[index]" class="service-card">
|
|
<!-- 服务日期 -->
|
|
<view class="service-section">
|
|
<view class="section-title">
|
|
<view class="title-indicator"></view>
|
|
<text>服务日期</text>
|
|
</view>
|
|
<view class="section-content date-content" :class="{bgSuccessQ : item.status}">
|
|
{{ item.fullDate }}
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 陪伴对象 -->
|
|
<view class="service-section">
|
|
<view class="section-title">
|
|
<view class="title-indicator"></view>
|
|
<text>陪伴对象</text>
|
|
<view class="collapse-icon" @click="togglePetList(index)">
|
|
{{ petListCollapsed[index] ? '展开' : '收起' }} <text class="arrow" :class="{'arrow-up': !petListCollapsed[index]}">▼</text>
|
|
</view>
|
|
</view>
|
|
<view class="section-content pet-list" :class="{bgSuccessQ : item.status}" v-if="!petListCollapsed[index]">
|
|
<view v-for="(pet, i) in item.petList" :key="i" class="pet-item">
|
|
<view class="pet-avatar">
|
|
<image :src="pet.avatar" mode="aspectFill" class="avatar-image"></image>
|
|
</view>
|
|
<view class="pet-info">
|
|
<view class="pet-name">
|
|
{{ pet.name }}
|
|
<text class="pet-gender" :class="{'pet-gender-male': pet.gender === 'male', 'pet-gender-female': pet.gender === 'female'}">
|
|
{{ pet.gender === 'male' ? '♂' : '♀' }}
|
|
</text>
|
|
</view>
|
|
<view class="pet-description">
|
|
{{ pet.breed }}{{ pet.bodyType }} | {{ pet.services.join(',') }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 上门地址 -->
|
|
<view class="service-section">
|
|
<view class="section-title">
|
|
<view class="title-indicator"></view>
|
|
<text>上门地址</text>
|
|
</view>
|
|
<view class="section-content address-content" :class="{bgSuccessQ : item.status}">
|
|
{{ item.addressDetail }}
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 操作按钮 -->
|
|
<view class="action-buttons">
|
|
<view class="btn btn-clock" :class="{bgSuccess : item.status}" @click="handleClock(item)">{{ item.status ? '打卡记录' : '打卡' }}</view>
|
|
<view class="btn btn-clock" :class="{bgSuccess : item.status}" @click="handlePetFile(item)">宠物档案</view>
|
|
<view class="btn btn-clock" :class="{bgSuccess : item.status}" @click="handleServiceFile(item)">服务档案</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed } from 'vue';
|
|
import { getOrderServiceText, getProductNameText } from '@/utils/serviceTime.js';
|
|
|
|
// 定义组件属性
|
|
const props = defineProps({
|
|
date: {
|
|
type: String,
|
|
default: '2024-12-08'
|
|
},
|
|
orderCount: {
|
|
type: Number,
|
|
default: 2
|
|
},
|
|
status : {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
current: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
list: {
|
|
type: Array,
|
|
default: () => []
|
|
}
|
|
});
|
|
|
|
// 宠物列表折叠状态 - 使用数组来单独控制每个卡片中的宠物列表
|
|
const petListCollapsed = ref([]);
|
|
|
|
// 服务卡片折叠状态 - 使用数组来单独控制每个卡片
|
|
const serviceCardCollapsed = ref([]);
|
|
|
|
// 切换宠物列表显示状态
|
|
const togglePetList = (index) => {
|
|
if (petListCollapsed.value[index] === undefined) {
|
|
petListCollapsed.value[index] = true;
|
|
} else {
|
|
petListCollapsed.value[index] = !petListCollapsed.value[index];
|
|
}
|
|
};
|
|
|
|
// 切换服务卡片显示状态
|
|
const toggleServiceCard = (index) => {
|
|
if (serviceCardCollapsed.value[index] === undefined) {
|
|
serviceCardCollapsed.value[index] = true;
|
|
} else {
|
|
serviceCardCollapsed.value[index] = !serviceCardCollapsed.value[index];
|
|
}
|
|
};
|
|
|
|
// 格式化日期
|
|
const formatDate = (dateString) => {
|
|
const date = new Date(dateString);
|
|
return {
|
|
day: date.getDate().toString().padStart(2, '0'),
|
|
month: (date.getMonth() + 1).toString().padStart(2, '0')
|
|
};
|
|
};
|
|
|
|
// 处理订单数据,转换为组件所需格式
|
|
const processedList = computed(() => {
|
|
return props.list.map(order => {
|
|
// 获取所有宠物信息
|
|
const petList = [];
|
|
|
|
let orderId = 0
|
|
|
|
let serviceId = 0
|
|
|
|
let status = 1
|
|
|
|
if (order.appletOrderItemDate && order.appletOrderItemDate.length > 0) {
|
|
order.appletOrderItemDate.forEach(item => {
|
|
if (item.orderServiceList && item.orderServiceList.petVo) {
|
|
const pet = item.orderServiceList.petVo;
|
|
const services = [];
|
|
|
|
// 获取服务名称
|
|
if (item.orderItemList && item.orderItemList.length > 0) {
|
|
item.orderItemList.forEach(orderItem => {
|
|
services.push(orderItem.productName);
|
|
orderId = orderItem.orderId
|
|
});
|
|
}
|
|
|
|
serviceId = item.id
|
|
|
|
if(item.status == 0){
|
|
status = 0
|
|
}
|
|
|
|
petList.push({
|
|
name: pet.name,
|
|
serviceId : item.id,
|
|
gender: pet.gender === '男生' ? 'male' : 'female',
|
|
breed: pet.breed,
|
|
bodyType: `(${pet.bodyType})`,
|
|
services: services,
|
|
avatar: pet.photo || (pet.petType === 'dog' ? '/static/images/ydd/dog.png' : '/static/images/ydd/cat.png')
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
return {
|
|
id: order.orderId,
|
|
orderId,
|
|
serviceId,
|
|
status,
|
|
address: order.cityAddress,
|
|
addressDetail: order.address,
|
|
fullDate: props.date.replace(/-/g, '/'),
|
|
petList: petList
|
|
};
|
|
});
|
|
});
|
|
|
|
// 按钮事件处理函数
|
|
const handleClock = (item) => {
|
|
|
|
// 根据订单状态确定跳转路径
|
|
const paths = [
|
|
`/otherPages/myOrdersManage/clock/index?id=${item.orderId}&itemID=${item.id}&serviceId=${item.serviceId}`,
|
|
`/otherPages/myOrdersManage/clock/index?isRead=true&id=${item.orderId}&itemID=${item.id}`,
|
|
];
|
|
|
|
uni.navigateTo({
|
|
url: props.status ? paths[0] : paths[1]
|
|
});
|
|
};
|
|
|
|
const handlePetFile = (item) => {
|
|
uni.navigateTo({
|
|
url: "/otherPages/orderTakingManage/pet/index?id=" + item.orderId
|
|
});
|
|
};
|
|
|
|
const handleServiceFile = (item) => {
|
|
|
|
|
|
|
|
uni.navigateTo({
|
|
url: "/otherPages/myOrdersManage/service/index?id=" + item.orderId
|
|
});
|
|
};
|
|
|
|
function getTopBgColor(){
|
|
return props.status ? '#FFAA48' : '#4CD964';
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
.bgSuccess{
|
|
background-color: #4CD964 !important;
|
|
}
|
|
.bgSuccessQ{
|
|
background-color: #4CD96422 !important;
|
|
}
|
|
|
|
.timeline-container {
|
|
position: relative;
|
|
padding: 20rpx;
|
|
margin-bottom: 30rpx;
|
|
|
|
.empty-state {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 80rpx 40rpx;
|
|
|
|
.empty-image {
|
|
width: 200rpx;
|
|
height: 200rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.empty-text {
|
|
color: #999;
|
|
font-size: 28rpx;
|
|
}
|
|
}
|
|
|
|
.date-header {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
.date-box {
|
|
width: 80rpx;
|
|
background-color: #ffffff;
|
|
border: 2px solid #333;
|
|
border-radius: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
margin-right: 20rpx;
|
|
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.05);
|
|
border-radius: 14rpx;
|
|
|
|
.date-box-color{
|
|
height: 20rpx;
|
|
width: 100%;
|
|
border-top-left-radius: 14rpx;
|
|
border-top-right-radius: 14rpx;
|
|
position: relative;
|
|
&::before{
|
|
content: '';
|
|
display: block;
|
|
background-color: #ddd;
|
|
width: 100%;
|
|
height: 26rpx;
|
|
top: 100%;
|
|
left: 0;
|
|
position: absolute;
|
|
}
|
|
}
|
|
|
|
.date-month-day {
|
|
position: relative;
|
|
font-size: 26rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
height: 50rpx;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
}
|
|
}
|
|
|
|
.status-tag {
|
|
background-color: #4CD96422;
|
|
color: #4CD964;
|
|
border: 4rpx solid #4CD964;
|
|
padding: 16rpx 26rpx;
|
|
border-radius: 14rpx;
|
|
font-size: 26rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
position: relative;
|
|
margin-left: 20rpx;
|
|
|
|
.status-icon {
|
|
width: 32rpx;
|
|
height: 32rpx;
|
|
margin-right: 8rpx;
|
|
}
|
|
&::after{
|
|
content: '';
|
|
display: block;
|
|
position: absolute;
|
|
width: 0;
|
|
height: 0;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
left: -16rpx;
|
|
border-top: 16rpx solid transparent;
|
|
border-bottom: 16rpx solid transparent;
|
|
border-right: 16rpx solid #4CD964;
|
|
}
|
|
|
|
&::before{
|
|
content: '';
|
|
display: block;
|
|
position: absolute;
|
|
width: 0;
|
|
height: 0;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
left: -12rpx;
|
|
border-top: 12rpx solid transparent;
|
|
border-bottom: 12rpx solid transparent;
|
|
border-right: 12rpx solid #4CD96422;
|
|
z-index: 1;
|
|
}
|
|
}
|
|
|
|
.status-tag-pending {
|
|
background-color: #FFAA4822;
|
|
color: #FFAA48;
|
|
border-color: #FFAA48;
|
|
&::after{
|
|
border-right-color: #FFAA48;
|
|
}
|
|
&::before{
|
|
border-right-color: #FFAA4822;
|
|
}
|
|
}
|
|
}
|
|
|
|
.timeline-body {
|
|
position: relative;
|
|
padding-left: 40rpx;
|
|
padding-bottom: 40rpx;
|
|
|
|
.timeline-line {
|
|
position: absolute;
|
|
left: 40rpx;
|
|
top: 0;
|
|
height: 100%;
|
|
width: 0;
|
|
border-left: 2rpx dashed #707070;
|
|
border-left-style: dashed;
|
|
border-image: repeating-linear-gradient(to bottom, #707070 0, #707070 8rpx, transparent 8rpx, transparent 20rpx) 1;
|
|
z-index: 0;
|
|
&::after{
|
|
content: '';
|
|
display: block;
|
|
position: absolute;
|
|
width: 8rpx;
|
|
height: 8rpx;
|
|
background-color: #000;
|
|
border: 2rpx solid #707070;
|
|
border-radius: 50%;
|
|
left: -7rpx;
|
|
top: 30rpx;
|
|
}
|
|
}
|
|
|
|
|
|
.time-point {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 20rpx;
|
|
position: relative;
|
|
z-index: 1;
|
|
|
|
.time-icon {
|
|
width: 60rpx;
|
|
height: 60rpx;
|
|
background-color: #fff;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
margin-right: 20rpx;
|
|
position: relative;
|
|
left: 20rpx;
|
|
|
|
.time-image {
|
|
width: 40rpx;
|
|
height: 40rpx;
|
|
}
|
|
}
|
|
|
|
.time-text {
|
|
font-size: 28rpx;
|
|
color: #333;
|
|
margin-left: 20rpx;
|
|
flex: 1;
|
|
}
|
|
|
|
.collapse-icon {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
padding: 0 20rpx;
|
|
|
|
.arrow {
|
|
transition: transform 0.3s;
|
|
display: inline-block;
|
|
}
|
|
|
|
.arrow-up {
|
|
transform: rotate(180deg);
|
|
}
|
|
}
|
|
}
|
|
|
|
.service-card {
|
|
background-color: #fff;
|
|
border-radius: 12rpx;
|
|
padding: 30rpx;
|
|
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
|
margin-left: 20rpx;
|
|
|
|
.service-section {
|
|
margin-bottom: 30rpx;
|
|
|
|
.section-title {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 15rpx;
|
|
|
|
.title-indicator {
|
|
width: 6rpx;
|
|
height: 30rpx;
|
|
background-color: #FFAA48;
|
|
margin-right: 15rpx;
|
|
}
|
|
|
|
text {
|
|
font-size: 28rpx;
|
|
color: #333;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.collapse-icon {
|
|
margin-left: auto;
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
|
|
.arrow {
|
|
transition: transform 0.3s;
|
|
display: inline-block;
|
|
}
|
|
|
|
.arrow-up {
|
|
transform: rotate(180deg);
|
|
}
|
|
}
|
|
}
|
|
|
|
.section-content {
|
|
padding: 0 15rpx;
|
|
background-color: #FFF9F0;
|
|
}
|
|
|
|
.date-content {
|
|
background-color: #FFF9F0;
|
|
padding: 20rpx;
|
|
border-radius: 8rpx;
|
|
font-size: 28rpx;
|
|
color: #333;
|
|
}
|
|
|
|
.pet-list {
|
|
padding: 15rpx;
|
|
.pet-item {
|
|
display: flex;
|
|
margin-bottom: 20rpx;
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.pet-avatar {
|
|
width: 80rpx;
|
|
height: 80rpx;
|
|
border-radius: 50%;
|
|
overflow: hidden;
|
|
margin-right: 20rpx;
|
|
|
|
.avatar-image {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
}
|
|
|
|
.pet-info {
|
|
flex: 1;
|
|
|
|
.pet-name {
|
|
font-size: 28rpx;
|
|
color: #333;
|
|
margin-bottom: 8rpx;
|
|
|
|
.pet-gender {
|
|
display: inline-block;
|
|
width: 32rpx;
|
|
height: 32rpx;
|
|
line-height: 32rpx;
|
|
text-align: center;
|
|
border-radius: 50%;
|
|
color: #fff;
|
|
font-size: 20rpx;
|
|
margin-left: 10rpx;
|
|
}
|
|
|
|
.pet-gender-male {
|
|
background-color: #4A90E2;
|
|
}
|
|
|
|
.pet-gender-female {
|
|
background-color: #FF6B9A;
|
|
}
|
|
}
|
|
|
|
.pet-description {
|
|
font-size: 24rpx;
|
|
color: #7D8196;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.address-content {
|
|
padding: 20rpx;
|
|
border-radius: 8rpx;
|
|
font-size: 28rpx;
|
|
color: #7D8196;
|
|
}
|
|
}
|
|
|
|
.action-buttons {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
|
|
.btn {
|
|
width: 30%;
|
|
height: 80rpx;
|
|
line-height: 80rpx;
|
|
text-align: center;
|
|
border-radius: 40rpx;
|
|
font-size: 28rpx;
|
|
}
|
|
|
|
.btn-clock {
|
|
background-color: #FFAA48;
|
|
color: #fff;
|
|
}
|
|
|
|
.btn-pet-file, .btn-service-file {
|
|
background-color: #F6F7FB;
|
|
color: #333;
|
|
border: 1px solid #E5E6EB;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|