Files
wagoo-douy3/src/pages/client/petOrder/index.vue
2026-03-06 13:41:22 +08:00

407 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="order-page-container">
<scroll-view class="tab-view" scroll-x="true" :show-scrollbar="false">
<view class="tab-view-content">
<view class="tab-item" v-for="item in tabList" :key="item.value" @click.stop="selectOrderStatus(item)">
<text class="fs-28 app-fc-normal" :class="{ 'tab-text ali-puhui-bold': item.value === currentStatus }">
{{ item.label }}
</text>
<view class="tab-line" :class="{ 'tab-selected-line': item.value === currentStatus }" />
</view>
</view>
</scroll-view>
<view class="order-content">
<view class="status-view-container" v-if="isLoading">
<uni-load-more status="loading" />
</view>
<view class="status-view-container" v-if="!isLoading && orderList.length === 0">
<uni-load-more status="noMore" />
</view>
<scroll-view
class="scroll-view"
scroll-y
v-if="!isLoading && orderList.length"
refresher-enabled
:refresher-triggered="isRefresh"
@refresherrefresh="refresherAction"
@scrolltolower="loadMoreAction"
refresher-background="transparent"
>
<!-- 根据 source 字段动态渲染不同的组件 -->
<block v-for="(item, index) in orderList" :key="item.order_id || index">
<!-- source 'pet_order' 时使用 reservation 组件 -->
<reservation
v-if="item.source === 'pet_order'"
:order-info="item"
@refresh-list="refresherAction"
@cancel-order="handleCancelOrder"
/>
<!-- source 'home_service' 时使用 home-service-order-item 组件 -->
<home-service-order-item
v-else-if="item.source === 'home_service'"
:order-info="item"
@refresh-list="refresherAction"
@cancel-order="handleCancelOrder"
/>
<!-- source 'home_training' 时使用 home-training-order-item 组件 -->
<home-training-order-item
v-else-if="item.source === 'home_training'"
:order-info="item"
@refresh-list="refresherAction"
@pay-now="handlePayNow"
@buy-course="handleBuyCourse"
@cancel-order="handleCancelOrder"
@view-contract="handleViewContract"
@goto-evaluate="handleGotoEvaluate"
/>
</block>
</scroll-view>
</view>
<!-- 取消预约确认弹窗 - 放在父组件中避免被 overflow: hidden 裁剪 -->
<pop-up-modal
v-if="isShowCancelModal"
content="确定要取消预约吗?"
@confirm="confirmCancelOrder"
@cancel="isShowCancelModal = false"
/>
</view>
</template>
<script>
import Reservation from './reservation.vue';
import HomeServiceOrderItem from './home-service-order-item.vue';
import HomeTrainingOrderItem from './home-training-order-item.vue';
import { showOrderStatus } from "@/pageHome/constants/home";
import { getOrderList, cancelHomeOrder, cancelTrainingOrder } from "@/api/order";
import { cancelPetOrderRefund } from "@/api/login";
import PopUpModal from "@/components/PopUpModal.vue";
export default {
name: 'index',
components: {
Reservation,
HomeServiceOrderItem,
HomeTrainingOrderItem,
PopUpModal
},
data() {
return {
tabList: showOrderStatus,
currentStatus: 0,
isLoading: true,
orderList: [],
pageNumber: 1,
pageSize: 10,
isRefresh: false,
isLoadMore: false,
isNoMore: false,
isShowCancelModal: false,
cancelOrderInfo: null,
};
},
onLoad(options) {
// 如果从外部传入状态,设置当前状态
if (options.status !== undefined) {
this.currentStatus = parseInt(options.status) || 0;
}
},
mounted() {
uni.$on("createRemarkSuccess", this.refresherAction);
uni.$on("refreshOrderList", this.refresherAction);
this.initData();
},
destroyed() {
uni.$off("createRemarkSuccess", this.refresherAction);
uni.$off("refreshOrderList", this.refresherAction);
},
watch: {
currentStatus: {
handler(newVal, oldVal) {
if (newVal !== oldVal && oldVal !== undefined) {
this.initData();
}
},
immediate: false
}
},
methods: {
selectOrderStatus(status) {
if (this.currentStatus === status.value) {
return;
}
this.currentStatus = status.value;
},
initData() {
this.isLoading = true;
this.pageNumber = 1;
this.isRefresh = false;
this.isLoadMore = false;
this.isNoMore = false;
this.orderList = [];
this.getData();
},
refresherAction() {
if (this.isRefresh) {
return;
}
this.pageNumber = 1;
this.isRefresh = true;
this.isLoadMore = false;
this.isNoMore = false;
this.getData();
},
loadMoreAction() {
console.log(this.isNoMore)
if (this.isNoMore) {
return;
}
this.pageNumber++;
this.getData();
},
getData() {
const value = uni.getStorageSync("userInfo");
const params = {
user_id: value.user_id,
status: this.currentStatus || 0,
page: this.pageNumber,
page_size: this.pageSize
};
getOrderList(params)
.then((res) => {
let list = res?.data || [];
if (this.pageNumber === 1) {
this.orderList = list;
} else {
this.orderList = [...this.orderList, ...list];
}
this.isRefresh = false;
this.isLoading = false;
this.isLoadMore = false;
this.isNoMore = list.length < 9;
})
.catch(() => {
if (this.pageNumber !== 1) {
this.pageNumber--;
}
this.isLoading = false;
this.isRefresh = false;
this.isLoadMore = false;
});
},
handleBookAgain(orderInfo) {
// 处理再次预约的逻辑
// 可以跳转到预约页面
console.log('再次预约', orderInfo);
// 例如uni.navigateTo({ url: '/pageHome/service/feeding?orderId=' + orderInfo.order_id });
},
handleViewReport(orderInfo) {
// 处理查看宠物报告的逻辑
console.log('查看宠物报告', orderInfo);
// 可以跳转到报告详情页面
// uni.navigateTo({ url: '/pages/client/report/detail?orderId=' + orderInfo.order_id });
},
handleBuyGoods(orderInfo) {
// 处理随车购商品的逻辑
uni.navigateTo({
url: `/pages/client/category/index?petOrderId=${orderInfo.order_id}&addressId=${orderInfo.address_id}`,
});
},
handleAddService(orderInfo) {
// 处理添加附加项的逻辑
console.log('添加附加项', orderInfo);
// 可以跳转到添加附加项页面或显示弹窗
},
handleCancelOrder(orderInfo) {
// 显示取消预约确认弹窗
this.cancelOrderInfo = orderInfo;
this.isShowCancelModal = true;
},
confirmCancelOrder() {
// 确认取消订单
if (!this.cancelOrderInfo) {
this.isShowCancelModal = false;
return;
}
const orderInfo = this.cancelOrderInfo;
this.isShowCancelModal = false;
uni.showLoading({
title: "正在取消订单",
mask: true,
});
// 根据订单类型调用不同的取消接口
let cancelPromise;
if (orderInfo.source === 'home_service') {
// 上门服务订单使用 cancelHomeOrder 接口
const orderId = orderInfo.home_service_order?.id;
cancelPromise = cancelHomeOrder(orderId);
} else if (orderInfo.source === 'pet_order') {
// pet_order 类型订单使用 cancelPetOrderRefund 接口
const orderId = orderInfo.pet_order?.order_id || orderInfo.order_id;
cancelPromise = cancelPetOrderRefund({ order_id: Number(orderId) });
} else {
// 上门训练订单使用 cancelTrainingOrder 接口
const orderId = orderInfo.home_training_order?.id;
cancelPromise = cancelTrainingOrder({ order_id: Number(orderId) });
}
cancelPromise
.then((res) => {
uni.hideLoading();
// 判断是否成功result === 'success'
if (res.result === 'success') {
this.cancelOrderInfo = null;
uni.showToast({
title:"取消成功",
icon: "success",
});
// 刷新订单列表
this.refresherAction();
} else {
// 失败:弹出错误信息
this.cancelOrderInfo = null;
uni.showToast({
title: res.msg || res.message || "取消订单失败",
icon: "none",
});
}
})
.catch((err) => {
uni.hideLoading();
this.cancelOrderInfo = null;
// 捕获异常时显示错误信息
const errorMsg = err?.msg || err?.message || err || "取消订单失败,请稍后重试";
uni.showToast({
title: errorMsg,
icon: "none",
});
});
},
handlePayNow(orderInfo) {
// 处理立即支付
console.log('立即支付', orderInfo);
// TODO: 实现支付逻辑
uni.showToast({
title: '支付功能开发中',
icon: 'none'
});
},
handleBuyCourse(orderInfo) {
// 处理购买课程
console.log('购买课程', orderInfo);
// TODO: 实现购买课程逻辑
uni.showToast({
title: '购买课程功能开发中',
icon: 'none'
});
},
handleViewContract(orderInfo) {
// 处理查看合同
console.log('查看合同', orderInfo);
// TODO: 实现查看合同逻辑,可能需要跳转到合同详情页
uni.showToast({
title: '查看合同功能开发中',
icon: 'none'
});
},
handleGotoEvaluate(orderInfo) {
// 处理去评价
const orderId = orderInfo.order_id || orderInfo.home_training_order?.order_id;
const pinglunId = orderInfo.pinglun_id;
if (pinglunId) {
// 如果已有评价,跳转到评价详情
uni.navigateTo({
url: `/pages/client/remark/details?remarkId=${pinglunId}`,
});
} else {
// 跳转到评价页面
// TODO: 确认订单类型常量
uni.navigateTo({
url: `/pages/client/order/remark?orderId=${orderId}&orderType=3`, // 3 可能是 home_training 的订单类型
});
}
}
}
}
</script>
<style lang="scss" scoped>
.order-page-container {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #f7f8fa;
}
.tab-view {
width: 100%;
height: 100rpx;
background-color: #ffffff;
white-space: nowrap;
border-top: 2rpx solid #f4f4f4;
flex-shrink: 0;
.tab-view-content {
display: inline-flex;
align-items: center;
height: 100%;
padding: 0 20rpx;
}
.tab-item {
display: inline-flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 20rpx;
flex-shrink: 0;
white-space: nowrap;
transition: 0.2ms all;
.tab-text {
color: $app_fc_main;
white-space: nowrap;
font-size: 32rpx;
}
}
.tab-line {
width: 24rpx;
height: 10rpx;
background-color: transparent;
margin-top: 18rpx;
border-radius: 100px;
}
.tab-selected-line {
background-color: $app_color_main;
}
}
.order-content {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
position: relative;
}
.status-view-container {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
.scroll-view {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
padding-bottom: 32rpx;
}
</style>