|
|
@ -2,43 +2,34 @@ |
|
|
|
<view class="order-list-page"> |
|
|
|
<!-- 顶部标签栏 --> |
|
|
|
<view class="order-tabs"> |
|
|
|
<view |
|
|
|
v-for="(tab, index) in tabs" |
|
|
|
:key="index" |
|
|
|
class="tab-item" |
|
|
|
:class="{active: currentTab === tab.value}" |
|
|
|
@click="switchTab(tab.value)" |
|
|
|
> |
|
|
|
<view v-for="(tab, index) in tabs" :key="index" class="tab-item" :class="{active: currentTab === tab.value}" |
|
|
|
@click="switchTab(tab.value)"> |
|
|
|
<text>{{tab.name}}</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 订单列表 --> |
|
|
|
<scroll-view |
|
|
|
scroll-y |
|
|
|
class="order-list-scroll" |
|
|
|
@scrolltolower="loadMore" |
|
|
|
@refresherrefresh="refresh" |
|
|
|
:refresher-enabled="true" |
|
|
|
:refresher-triggered="refreshing" |
|
|
|
> |
|
|
|
<scroll-view scroll-y class="order-list-scroll" @scrolltolower="loadMore" @refresherrefresh="refresh" |
|
|
|
:refresher-enabled="true" :refresher-triggered="refreshing"> |
|
|
|
<view class="order-list"> |
|
|
|
<!-- 订单卡片 --> |
|
|
|
<view class="order-card" v-for="(order, index) in orderList" :key="index"> |
|
|
|
<view class="order-header"> |
|
|
|
<text>{{ tabs[order.status - 1].name }}</text> |
|
|
|
<view class="order-status"> |
|
|
|
<text>{{order.statusText}}</text> |
|
|
|
<text v-if="order.teacherId">指定伴宠师下单</text> |
|
|
|
<text v-else>系统下单</text> |
|
|
|
</view> |
|
|
|
<view class="order-amount"> |
|
|
|
<text>金额:</text> |
|
|
|
<text class="amount-value">¥{{order.amount}}</text> |
|
|
|
<text class="amount-value">¥{{order.payAmount}}</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 宠物信息 --> |
|
|
|
<view class="pet-info" v-for="(pet, petIndex) in order.pets" :key="petIndex"> |
|
|
|
<view class="pet-info" v-for="(pet, petIndex) in order.petVOList" :key="petIndex"> |
|
|
|
<view class="pet-avatar"> |
|
|
|
<image :src="pet.avatar || '/static/images/personal/pet.png'" mode="aspectFill"></image> |
|
|
|
<image :src="pet.photo || '/static/images/personal/pet.png'" mode="aspectFill"></image> |
|
|
|
<view class="pet-tag" v-if="pet.tag"> |
|
|
|
<text>{{pet.tag}}</text> |
|
|
|
</view> |
|
|
@ -46,27 +37,30 @@ |
|
|
|
<view class="pet-details"> |
|
|
|
<view class="pet-name-gender" style="display: flex; align-items: center;"> |
|
|
|
<text class="pet-name">{{pet.name}}</text> |
|
|
|
<view class="pet-gender" style="margin-left: 10rpx; display: flex; align-items: center;"> |
|
|
|
<image :src="pet.gender=='男生'?'/static/images/details/boy.svg':'/static/images/details/girl.svg'" style="width: 24rpx; height: 24rpx;" alt="sex"></image> |
|
|
|
<view class="pet-gender" |
|
|
|
style="margin-left: 10rpx; display: flex; align-items: center;"> |
|
|
|
<image |
|
|
|
:src="pet.gender=='男生'?'/static/images/details/boy.svg':'/static/images/details/girl.svg'" |
|
|
|
style="width: 24rpx; height: 24rpx;" alt="sex"></image> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<text class="pet-service">{{pet.serviceTime}}</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 订单信息 --> |
|
|
|
<view class="order-info"> |
|
|
|
<text class="order-time">下单时间: {{order.orderTime}}</text> |
|
|
|
<text class="order-time">下单时间: {{order.createTime}}</text> |
|
|
|
<view class="companion-info"> |
|
|
|
<text>伴宠师: {{order.companionName}}</text> |
|
|
|
<text v-if="order.companionNote">({{order.companionNote}})</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 订单操作 --> |
|
|
|
<view class="order-actions"> |
|
|
|
<view class="action-btn details-btn" v-if="order.status == 0" |
|
|
|
@click="$refs.cancelOrderPopup.open()"> |
|
|
|
<view class="action-btn details-btn" v-if="order.status == 0" |
|
|
|
@click="$refs.cancelOrderPopup.open()"> |
|
|
|
<text>取消订单</text> |
|
|
|
</view> |
|
|
|
<view class="action-btn details-btn" @click="viewOrderDetails(order.id)"> |
|
|
@ -80,17 +74,17 @@ |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 加载更多 --> |
|
|
|
<view class="loading-more" v-if="orderList.length > 0 && hasMore"> |
|
|
|
<text>加载中...</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 无更多数据 --> |
|
|
|
<view class="no-more" v-if="orderList.length > 0 && !hasMore"> |
|
|
|
<text>没有更多订单了</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 无订单提示 --> |
|
|
|
<view class="no-order" v-if="orderList.length === 0 && !loading"> |
|
|
|
<image src="/static/images/personal/no-data.png" mode="aspectFit" class="no-data-image"></image> |
|
|
@ -100,27 +94,27 @@ |
|
|
|
</scroll-view> |
|
|
|
|
|
|
|
<!-- 取消订单弹窗 --> |
|
|
|
<cancel-order-popup |
|
|
|
ref="cancelOrderPopup" |
|
|
|
@cancel="handleCancelOrder" |
|
|
|
></cancel-order-popup> |
|
|
|
|
|
|
|
<cancel-order-popup ref="cancelOrderPopup" @cancel="handleCancelOrder"></cancel-order-popup> |
|
|
|
|
|
|
|
<!-- 客服组件 --> |
|
|
|
<Kefu></Kefu> |
|
|
|
|
|
|
|
<!-- 伴宠师选择弹窗 --> |
|
|
|
<companion-select-popup |
|
|
|
ref="companionSelectPopup"/> |
|
|
|
<companion-select-popup ref="companionSelectPopup" /> |
|
|
|
</view> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script> |
|
|
|
import Kefu from '@/pages/common/kefu.vue' |
|
|
|
import { getOrderList } from "@/api/system/user.js" |
|
|
|
import { getOpenIdKey } from '@/utils/auth' |
|
|
|
import { |
|
|
|
getOrderList |
|
|
|
} from "@/api/system/user.js" |
|
|
|
import { |
|
|
|
getOpenIdKey |
|
|
|
} from '@/utils/auth' |
|
|
|
import CancelOrderPopup from '@/pages_order/components/order/CancelOrderPopup.vue' |
|
|
|
import CompanionSelectPopup from '@/pages_order/components/order/CompanionSelectPopup.vue' |
|
|
|
|
|
|
|
// import { getOrderServiceText, getProductNameText } from '@/utils/serviceTime.js' |
|
|
|
export default { |
|
|
|
components: { |
|
|
|
Kefu, |
|
|
@ -129,14 +123,28 @@ |
|
|
|
}, |
|
|
|
data() { |
|
|
|
return { |
|
|
|
tabs: [ |
|
|
|
{ name: '全部', value: '' }, |
|
|
|
{ name: '待付款', value: '0' }, |
|
|
|
{ name: '已接单', value: '1' }, |
|
|
|
{ name: '服务中', value: '2' }, |
|
|
|
{ name: '已完成', value: '3' } |
|
|
|
tabs: [{ |
|
|
|
name: '全部', |
|
|
|
value: -1 |
|
|
|
}, |
|
|
|
{ |
|
|
|
name: '待付款', |
|
|
|
value: 0 |
|
|
|
}, |
|
|
|
{ |
|
|
|
name: '已接单', |
|
|
|
value: 1 |
|
|
|
}, |
|
|
|
{ |
|
|
|
name: '服务中', |
|
|
|
value: 2 |
|
|
|
}, |
|
|
|
{ |
|
|
|
name: '已完成', |
|
|
|
value: 3 |
|
|
|
} |
|
|
|
], |
|
|
|
currentTab: '', |
|
|
|
currentTab: -1, |
|
|
|
orderList: [], |
|
|
|
page: 1, |
|
|
|
size: 10, |
|
|
@ -145,46 +153,43 @@ |
|
|
|
refreshing: false, |
|
|
|
currentOrder: null, |
|
|
|
// 示例数据,实际应从API获取 |
|
|
|
exampleData: [ |
|
|
|
{ |
|
|
|
id: '1', |
|
|
|
status: '0', |
|
|
|
statusText: '待付款', |
|
|
|
amount: '264', |
|
|
|
pets: [ |
|
|
|
{ |
|
|
|
name: '小咪', |
|
|
|
avatar: '/static/images/personal/pet.png', |
|
|
|
tag: '猫', |
|
|
|
gender: '女生', |
|
|
|
serviceTime: '专业喂养2天: 03-20,03-22' |
|
|
|
}, |
|
|
|
{ |
|
|
|
name: '小汪', |
|
|
|
avatar: '/static/images/personal/pet.png', |
|
|
|
tag: '狗', |
|
|
|
gender: '男生', |
|
|
|
serviceTime: '专业喂养2天: 03-20,03-22' |
|
|
|
} |
|
|
|
], |
|
|
|
orderTime: '2025-12-14 18:23:06', |
|
|
|
companionName: '张三', |
|
|
|
companionNote: '伴宠师名称暂不可见' |
|
|
|
} |
|
|
|
] |
|
|
|
exampleData: [{ |
|
|
|
id: '1', |
|
|
|
status: '0', |
|
|
|
statusText: '待付款', |
|
|
|
amount: '264', |
|
|
|
pets: [{ |
|
|
|
name: '小咪', |
|
|
|
avatar: '/static/images/personal/pet.png', |
|
|
|
tag: '猫', |
|
|
|
gender: '女生', |
|
|
|
serviceTime: '专业喂养2天: 03-20,03-22' |
|
|
|
}, |
|
|
|
{ |
|
|
|
name: '小汪', |
|
|
|
avatar: '/static/images/personal/pet.png', |
|
|
|
tag: '狗', |
|
|
|
gender: '男生', |
|
|
|
serviceTime: '专业喂养2天: 03-20,03-22' |
|
|
|
} |
|
|
|
], |
|
|
|
orderTime: '2025-12-14 18:23:06', |
|
|
|
companionName: '张三', |
|
|
|
companionNote: '伴宠师名称暂不可见' |
|
|
|
}] |
|
|
|
}; |
|
|
|
}, |
|
|
|
methods: { |
|
|
|
// 切换标签 |
|
|
|
switchTab(tabValue) { |
|
|
|
if (this.currentTab === tabValue) return; |
|
|
|
// if (this.currentTab === tabValue) return; |
|
|
|
this.currentTab = tabValue; |
|
|
|
this.orderList = []; |
|
|
|
this.page = 1; |
|
|
|
this.hasMore = true; |
|
|
|
this.getOrderList(); |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
// 下拉刷新 |
|
|
|
refresh() { |
|
|
|
this.refreshing = true; |
|
|
@ -197,37 +202,37 @@ |
|
|
|
this.refreshing = false; |
|
|
|
}); |
|
|
|
}, |
|
|
|
|
|
|
|
handleCancelOrder(){ |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
handleCancelOrder() { |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
// 加载更多 |
|
|
|
loadMore() { |
|
|
|
if (this.loading || !this.hasMore) return; |
|
|
|
this.page++; |
|
|
|
this.getOrderList(); |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
// 查看订单详情 |
|
|
|
viewOrderDetails(orderId) { |
|
|
|
uni.navigateTo({ |
|
|
|
url: `/pages_order/order/orderDetail?id=${orderId}` |
|
|
|
}); |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
// 去付款 |
|
|
|
goToPay(orderId) { |
|
|
|
uni.navigateTo({ |
|
|
|
url: `/pages/details/order?id=${orderId}` |
|
|
|
}); |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
// 获取订单列表 |
|
|
|
getOrderList() { |
|
|
|
if (this.loading) return Promise.reject(); |
|
|
|
this.loading = true; |
|
|
|
|
|
|
|
|
|
|
|
// 构建请求参数 |
|
|
|
const params = { |
|
|
|
status: this.currentTab, |
|
|
@ -236,47 +241,46 @@ |
|
|
|
size: this.size |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// 实际API调用 |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
// 模拟API调用,实际项目中应使用真实API |
|
|
|
setTimeout(() => { |
|
|
|
try { |
|
|
|
// 模拟数据,实际应调用API |
|
|
|
if (this.page === 1) { |
|
|
|
this.orderList = [...this.exampleData]; |
|
|
|
} else if (this.page < 3) { |
|
|
|
this.orderList = [...this.orderList, ...this.exampleData]; |
|
|
|
} else { |
|
|
|
this.hasMore = false; |
|
|
|
} |
|
|
|
|
|
|
|
// 实际API调用应该是这样: |
|
|
|
// getOrderList(params).then(res => { |
|
|
|
// if (res && res.code === 200) { |
|
|
|
// const newList = res.data.records || []; |
|
|
|
// if (this.page === 1) { |
|
|
|
// this.orderList = newList; |
|
|
|
// } else { |
|
|
|
// this.orderList = [...this.orderList, ...newList]; |
|
|
|
// } |
|
|
|
// this.hasMore = newList.length === this.size; |
|
|
|
// } else { |
|
|
|
// this.hasMore = false; |
|
|
|
// } |
|
|
|
// this.loading = false; |
|
|
|
// resolve(); |
|
|
|
// }).catch(err => { |
|
|
|
// this.loading = false; |
|
|
|
// reject(err); |
|
|
|
// }); |
|
|
|
|
|
|
|
this.loading = false; |
|
|
|
resolve(); |
|
|
|
} catch (err) { |
|
|
|
this.loading = false; |
|
|
|
reject(err); |
|
|
|
// return new Promise((resolve, reject) => { |
|
|
|
// // 模拟API调用,实际项目中应使用真实API |
|
|
|
// setTimeout(() => { |
|
|
|
// try { |
|
|
|
// // 模拟数据,实际应调用API |
|
|
|
// if (this.page === 1) { |
|
|
|
// this.orderList = [...this.exampleData]; |
|
|
|
// } else if (this.page < 3) { |
|
|
|
// this.orderList = [...this.orderList, ...this.exampleData]; |
|
|
|
// } else { |
|
|
|
// this.hasMore = false; |
|
|
|
// } |
|
|
|
// this.loading = false; |
|
|
|
// resolve(); |
|
|
|
// } catch (err) { |
|
|
|
// this.loading = false; |
|
|
|
// reject(err); |
|
|
|
// } |
|
|
|
// }, 500); |
|
|
|
// }); |
|
|
|
// 实际API调用应该是这样: |
|
|
|
return getOrderList(params).then(res => { |
|
|
|
if (res.content) { |
|
|
|
const newList = res.content || []; |
|
|
|
if (this.page === 1) { |
|
|
|
this.orderList = newList; |
|
|
|
} else { |
|
|
|
this.orderList = [...this.orderList, ...newList]; |
|
|
|
} |
|
|
|
}, 500); |
|
|
|
this.hasMore = newList.length === this.size; |
|
|
|
} else { |
|
|
|
this.hasMore = false; |
|
|
|
} |
|
|
|
this.loading = false; |
|
|
|
resolve(); |
|
|
|
}).catch(err => { |
|
|
|
this.loading = false; |
|
|
|
reject(err); |
|
|
|
}); |
|
|
|
}, |
|
|
|
|
|
|
@ -301,7 +305,7 @@ |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.order-tabs { |
|
|
|
display: flex; |
|
|
|
justify-content: space-around; |
|
|
@ -309,7 +313,7 @@ |
|
|
|
height: 88rpx; |
|
|
|
background-color: #FFBF60; |
|
|
|
color: #FFFFFF; |
|
|
|
|
|
|
|
|
|
|
|
.tab-item { |
|
|
|
padding: 0 20rpx; |
|
|
|
height: 100%; |
|
|
@ -318,10 +322,10 @@ |
|
|
|
justify-content: center; |
|
|
|
font-size: 28rpx; |
|
|
|
position: relative; |
|
|
|
|
|
|
|
|
|
|
|
&.active { |
|
|
|
font-weight: bold; |
|
|
|
|
|
|
|
|
|
|
|
&::after { |
|
|
|
content: ''; |
|
|
|
position: absolute; |
|
|
@ -336,67 +340,72 @@ |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.order-list-scroll { |
|
|
|
flex: 1; |
|
|
|
width: 100%; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.order-list { |
|
|
|
padding: 20rpx; |
|
|
|
padding-bottom: 40rpx; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.order-card { |
|
|
|
background-color: #FFFFFF; |
|
|
|
border-radius: 20rpx; |
|
|
|
padding: 30rpx; |
|
|
|
margin-bottom: 20rpx; |
|
|
|
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.order-header { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
margin-bottom: 20rpx; |
|
|
|
|
|
|
|
background-color: #FFF4E5; |
|
|
|
padding: 30rpx; |
|
|
|
padding-bottom: 20rpx; |
|
|
|
|
|
|
|
.order-status { |
|
|
|
background-color: #FFF5E6; |
|
|
|
color: #FFAA48; |
|
|
|
color: #A94F20; |
|
|
|
padding: 6rpx 16rpx; |
|
|
|
border-radius: 20rpx; |
|
|
|
font-size: 24rpx; |
|
|
|
background-color: #FFE0BF; |
|
|
|
margin-right: auto; |
|
|
|
margin-left: 20rpx; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.order-amount { |
|
|
|
font-size: 28rpx; |
|
|
|
color: #333; |
|
|
|
|
|
|
|
|
|
|
|
.amount-value { |
|
|
|
color: #FF5252; |
|
|
|
font-weight: bold; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.pet-info { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
margin-bottom: 20rpx; |
|
|
|
|
|
|
|
padding: 30rpx; |
|
|
|
padding-bottom: 20rpx; |
|
|
|
padding-top: 20rpx; |
|
|
|
|
|
|
|
.pet-avatar { |
|
|
|
position: relative; |
|
|
|
width: 80rpx; |
|
|
|
height: 80rpx; |
|
|
|
margin-right: 20rpx; |
|
|
|
|
|
|
|
|
|
|
|
image { |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
border-radius: 50%; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.pet-tag { |
|
|
|
position: absolute; |
|
|
|
right: -10rpx; |
|
|
@ -409,17 +418,17 @@ |
|
|
|
line-height: 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.pet-details { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
|
|
|
|
|
|
|
|
.pet-name { |
|
|
|
font-size: 28rpx; |
|
|
|
color: #333; |
|
|
|
font-weight: bold; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.pet-service { |
|
|
|
font-size: 24rpx; |
|
|
|
color: #666; |
|
|
@ -427,17 +436,19 @@ |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.order-info { |
|
|
|
margin-bottom: 30rpx; |
|
|
|
|
|
|
|
padding: 30rpx; |
|
|
|
padding-bottom: 20rpx; |
|
|
|
padding-top: 20rpx; |
|
|
|
|
|
|
|
.order-time { |
|
|
|
font-size: 24rpx; |
|
|
|
color: #999; |
|
|
|
display: block; |
|
|
|
margin-bottom: 10rpx; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.companion-info { |
|
|
|
font-size: 24rpx; |
|
|
|
color: #999; |
|
|
@ -446,38 +457,41 @@ |
|
|
|
border-radius: 10rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.order-actions { |
|
|
|
padding: 30rpx; |
|
|
|
padding-top: 20rpx; |
|
|
|
display: flex; |
|
|
|
justify-content: flex-end; |
|
|
|
align-items: center; |
|
|
|
|
|
|
|
|
|
|
|
.action-btn { |
|
|
|
padding: 16rpx 30rpx; |
|
|
|
border-radius: 30rpx; |
|
|
|
font-size: 26rpx; |
|
|
|
margin-left: 20rpx; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.details-btn { |
|
|
|
background-color: #FFFFFF; |
|
|
|
color: #666; |
|
|
|
border: 1px solid #DDDDDD; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.pay-btn { |
|
|
|
background-color: #FFAA48; |
|
|
|
color: #FFFFFF; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.loading-more, .no-more { |
|
|
|
|
|
|
|
.loading-more, |
|
|
|
.no-more { |
|
|
|
text-align: center; |
|
|
|
padding: 20rpx 0; |
|
|
|
color: #999; |
|
|
|
font-size: 24rpx; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.no-order { |
|
|
|
text-align: center; |
|
|
|
padding: 100rpx 0; |
|
|
@ -486,7 +500,7 @@ |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
align-items: center; |
|
|
|
|
|
|
|
|
|
|
|
.no-data-image { |
|
|
|
width: 200rpx; |
|
|
|
height: 200rpx; |
|
|
|