- <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>
|