This commit is contained in:
2026-03-06 13:41:22 +08:00
commit f39c6a705f
394 changed files with 159599 additions and 0 deletions

View File

@ -0,0 +1,406 @@
<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>