feat: 订单退款功能对接

This commit is contained in:
duanshuwen
2025-09-29 21:59:07 +08:00
parent 2580e7a266
commit 9cc7b48d36
5 changed files with 212 additions and 299 deletions

View File

@@ -39,12 +39,7 @@
<script setup>
import { defineProps, computed, ref, defineEmits } from "vue";
import {
preOrder,
orderPayNow,
orderCancel,
orderRefund,
} from "@/request/api/OrderApi";
import { orderPayNow } from "@/request/api/OrderApi";
// 支付方式映射常量
const PAY_WAY_MAP = {
@@ -57,7 +52,7 @@ const PAY_WAY_MAP = {
const isLoading = ref(false);
// 定义事件发射器
const emit = defineEmits(['show-refund-popup']);
const emit = defineEmits(["show-refund-popup"]);
const props = defineProps({
orderData: {
@@ -116,7 +111,7 @@ const handleButtonClick = async () => {
if (status === "2") {
// 情况2待使用状态显示退款弹窗
emit('show-refund-popup');
emit("show-refund-popup");
return; // 直接返回,不执行后续代码
}

View File

@@ -3,61 +3,68 @@
<view class="refund-popup">
<!-- 头部卡通形象 -->
<image
src="@/static/dh.png"
:src="commodityPurchaseInstruction.refundLogo"
class="refund-popup__avatar"
mode="widthFix"
mode="aspectFill"
/>
<!-- 内容区域 -->
<view class="refund-popup__content">
<!-- 主标题 -->
<view class="refund-popup__title">{{ currentTitle }}</view>
<view class="refund-popup__title">
{{ commodityPurchaseInstruction.refundTitle }}
</view>
<!-- 金额显示 -->
<view class="refund-popup__amount" v-if="showAmount">
<view class="refund-popup__amount" v-if="isRefundable">
<text class="amount-symbol">¥</text>
<text class="amount-value">{{ refundAmount }}</text>
<text class="amount-unit"></text>
</view>
<view class="refund-popup__amount-label" v-if="showAmount"
<view class="refund-popup__amount-label" v-if="isRefundable"
>可退金额</view
>
<!-- 描述信息 -->
<view class="refund-popup__description" v-if="currentDescription">
{{ currentDescription }}
</view>
<!-- 退款政策详情 -->
<view class="refund-popup__policy" v-if="showPolicy">
<view class="refund-popup__policy" v-if="showRefundPolicy">
<view class="policy-title">退订政策</view>
<view class="policy-list">
<view
class="policy-item"
v-for="(rule, index) in currentRules"
:key="index"
>
{{ rule }}
</view>
<view class="policy-content">
{{ commodityPurchaseInstruction.refundContent }}
</view>
</view>
</view>
<!-- 按钮区域 -->
<view class="refund-popup__actions">
<view class="action-btn secondary-btn" @click="handlePolicyClick">
{{ leftButtonText }}
<view
v-if="!showRefundPolicy"
class="action-btn secondary-btn"
@click="handlePolicyClick"
>
退订政策
</view>
<view class="action-btn primary-btn" @click="handleConfirmClick">
{{ rightButtonText }}
<view
class="action-btn primary-btn"
@click="handleConfirmClick(btnText)"
>
{{ btnText }}
</view>
</view>
<!-- 关闭按钮 -->
<uni-icons
class="refund-popup__close"
type="close"
size="40"
color="#fff"
@click="handleClose"
/>
</view>
</uni-popup>
</template>
<script setup>
import { ref, computed, watch, shallowRef } from "vue";
import { ref, computed, watch } from "vue";
// Props定义
const props = defineProps({
@@ -66,107 +73,44 @@ const props = defineProps({
type: Boolean,
default: false,
},
// 退款类型
refundType: {
type: String,
default: "no_refund",
validator: (value) =>
["no_refund", "all_refund", "anytime_refund"].includes(value),
},
// 可退金额
refundAmount: {
type: Number,
default: 0,
},
// 退款规则列表
refundRules: {
type: Array,
default: () => [],
},
// 自定义标题
title: {
type: String,
default: "",
},
// 自定义描述
description: {
type: String,
default: "",
// 订单数据
orderData: {
type: Object,
default: () => {},
},
});
// Events定义
const emit = defineEmits([
"update:modelValue",
"policy-click",
"confirm-click",
"close",
]);
const emit = defineEmits(["update:modelValue", "confirm", "close"]);
// 弹窗引用
const popupRef = ref(null);
// 退款政策是否显示
const showRefundPolicy = ref(false);
// 退款场景配置使用shallowRef优化性能
const refundScenarios = shallowRef({
no_refund: {
title: "您在入住日期12小时以内申请退款不可退款,如有疑问请咨询客服",
description: "",
showAmount: false,
showPolicy: false,
leftButton: "退订政策",
rightButton: "我知道了",
rules: [],
},
all_refund: {
title: "您在入住日期24小时内申请退款可退还100%金额",
description: "",
showAmount: true,
showPolicy: true,
leftButton: "退订政策",
rightButton: "点击退款",
rules: [],
},
anytime_refund: {
title: "该商品未使用随时可退",
description: "",
showAmount: true,
showPolicy: false,
leftButton: "退订政策",
rightButton: "点击退款",
rules: [],
},
});
// 计算属性
const currentScenario = computed(
() =>
refundScenarios.value[props.refundType] || refundScenarios.value.no_refund
);
const currentTitle = computed(() => props.title || currentScenario.value.title);
const currentDescription = computed(
() => props.description || currentScenario.value.description
);
const currentRules = computed(() => {
if (props.refundRules.length) {
return props.refundRules;
// 退款金额
const refundAmount = computed(() => {
if (props.orderData.payAmt) {
return parseFloat(Number(props.orderData.payAmt) || 0);
}
return currentScenario.value.rules;
return 0;
});
const showAmount = computed(
() => currentScenario.value.showAmount && props.refundAmount > 0
);
// 是否可退款
const isRefundable = computed(() => !props.orderData.refundable);
const showPolicy = computed(
() => currentScenario.value.showPolicy && currentRules.value.length > 0
);
// 按钮文件
const btnText = computed(() => (isRefundable.value ? "点击退款" : "我知道了"));
const leftButtonText = computed(() => currentScenario.value.leftButton);
// 获取退款模板
const commodityPurchaseInstruction = computed(() => {
if (props.orderData.commodityPurchaseInstruction) {
return props.orderData.commodityPurchaseInstruction;
}
const rightButtonText = computed(() => currentScenario.value.rightButton);
return {};
});
// 方法定义
const show = () => popupRef.value.open();
@@ -186,28 +130,21 @@ watch(
{ immediate: true }
);
// 监听退款金额变化,进行数据验证
watch(
() => props.refundAmount,
(newVal) => {
if (newVal < 0) {
console.warn("RefundPopup: 退款金额不能为负数");
}
},
{ immediate: true }
);
const handleClose = () => {
showRefundPolicy.value = false;
emit("update:modelValue", false);
emit("close");
};
const handlePolicyClick = () => {
emit("policy-click");
showRefundPolicy.value = true;
};
const handleConfirmClick = () => {
emit("confirm-click");
const handleConfirmClick = (text) => {
if (text === "点击退款") {
emit("confirm", props.orderData);
}
handleClose();
};
</script>

View File

@@ -13,7 +13,7 @@
width: 132px;
height: 132px;
position: absolute;
top: -45px;
top: -75px;
left: 50%;
transform: translateX(-50%);
}
@@ -62,14 +62,6 @@
margin-bottom: 16px;
}
&__description {
font-size: 14px;
color: #333333;
line-height: 1.5;
margin-bottom: 16px;
text-align: left;
}
&__policy {
text-align: left;
margin-bottom: 16px;
@@ -81,17 +73,11 @@
margin-bottom: 8px;
}
.policy-list {
.policy-item {
.policy-content {
font-size: 12px;
color: #333333;
line-height: 22px;
text-align: justify;
&:last-child {
margin-bottom: 0;
}
}
}
}
@@ -133,6 +119,16 @@
}
}
}
// 关闭按钮
&__close {
position: absolute;
bottom: -60px;
left: 50%;
transform: translateX(-50%);
width: 40px;
height: 40px;
}
}
// 动画效果

View File

@@ -17,10 +17,8 @@
<!-- 退款状态显示 -->
<RefundPopup
v-model="refundVisible"
:refund-type="refundType"
:refund-amount="refundAmount"
@policy-click="viewRefundPolicy"
@confirm-click="handleRefundConfirm"
:orderData="orderData"
@confirm="handleRefundConfirm"
/>
</view>
</template>
@@ -38,15 +36,12 @@ import OrderInfo from "./components/OrderInfo/index.vue";
import RefundPopup from "./components/RefundPopup/index.vue";
const refundVisible = ref(false);
const refundType = ref("free_cancel"); // 默认退款类型
const refundAmount = ref(0); // 退款金额
const orderData = ref({});
onLoad(async ({ orderId }) => {
const res = await userOrderDetail({ orderId });
orderData.value = res.data;
// 设置退款金额为订单支付金额
refundAmount.value = parseFloat(res.data.payAmt || 0);
console.log(res);
});
@@ -62,17 +57,11 @@ const showRefundPopup = () => {
refundVisible.value = true;
};
// 查看退款政策
const viewRefundPolicy = () => {
console.log("查看退款政策");
// 这里可以跳转到退款政策页面或显示详细政策
};
// 确认退款
const handleRefundConfirm = async () => {
const handleRefundConfirm = async ({ orderId }) => {
try {
// 调用退款API
await orderRefund({ orderId: orderData.value.orderId });
await orderRefund({ orderId });
uni.showToast({
title: "退款申请已提交",
@@ -80,10 +69,8 @@ const handleRefundConfirm = async () => {
});
// 刷新订单状态
const res = await userOrderDetail({ orderId: orderData.value.orderId });
const res = await userOrderDetail({ orderId });
orderData.value = res.data;
// 更新退款金额
refundAmount.value = parseFloat(res.data.payAmt || 0);
} catch (error) {
console.error("退款失败:", error);
uni.showToast({

View File

@@ -41,9 +41,7 @@
.wrapper {
box-sizing: border-box;
padding-left: 12px;
padding-right: 12px;
padding-top: 12px;
padding: 12px;
}
.good-info-wrapper {
@@ -160,7 +158,7 @@
box-sizing: border-box;
padding-left: 12px;
padding-right: 12px;
padding-bottom: var(--safe-area-inset-bottom);
padding-bottom: 24px;
.left {
display: flex;