407 lines
12 KiB
Vue
407 lines
12 KiB
Vue
<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>
|