feat: 新增订单详情退款弹窗

This commit is contained in:
duanshuwen
2025-08-07 20:03:03 +08:00
parent a8a5a90d5e
commit 72c761428b
10 changed files with 1345 additions and 97 deletions

View File

@@ -0,0 +1,217 @@
<template>
<uni-popup ref="popupRef" type="center" @maskClick="handleClose">
<view class="refund-popup">
<!-- 头部卡通形象 -->
<image
src="@/static/dh.png"
class="refund-popup__avatar"
mode="widthFix"
/>
<!-- 内容区域 -->
<view class="refund-popup__content">
<!-- 主标题 -->
<view class="refund-popup__title">{{ currentTitle }}</view>
<!-- 金额显示 -->
<view class="refund-popup__amount" v-if="showAmount">
<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
>
<!-- 描述信息 -->
<view class="refund-popup__description" v-if="currentDescription">
{{ currentDescription }}
</view>
<!-- 退款政策详情 -->
<view class="refund-popup__policy" v-if="showPolicy">
<view class="policy-title">退订政策</view>
<view class="policy-list">
<view
class="policy-item"
v-for="(rule, index) in currentRules"
:key="index"
>
{{ rule }}
</view>
</view>
</view>
</view>
<!-- 按钮区域 -->
<view class="refund-popup__actions">
<view class="action-btn secondary-btn" @click="handlePolicyClick">
{{ leftButtonText }}
</view>
<view class="action-btn primary-btn" @click="handleConfirmClick">
{{ rightButtonText }}
</view>
</view>
</view>
</uni-popup>
</template>
<script setup>
import { ref, computed, watch, shallowRef } from "vue";
// Props定义
const props = defineProps({
// 弹窗显示状态
modelValue: {
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: "",
},
});
// Events定义
const emit = defineEmits([
"update:modelValue",
"policy-click",
"confirm-click",
"close",
]);
// 弹窗引用
const popupRef = ref(null);
// 退款场景配置使用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;
}
return currentScenario.value.rules;
});
const showAmount = computed(
() => currentScenario.value.showAmount && props.refundAmount > 0
);
const showPolicy = computed(
() => currentScenario.value.showPolicy && currentRules.value.length > 0
);
const leftButtonText = computed(() => currentScenario.value.leftButton);
const rightButtonText = computed(() => currentScenario.value.rightButton);
// 方法定义
const show = () => popupRef.value.open();
const hide = () => popupRef.value.close();
// 监听modelValue变化
watch(
() => props.modelValue,
(newVal) => {
if (newVal) {
show();
} else {
hide();
}
},
{ immediate: true }
);
// 监听退款金额变化,进行数据验证
watch(
() => props.refundAmount,
(newVal) => {
if (newVal < 0) {
console.warn("RefundPopup: 退款金额不能为负数");
}
},
{ immediate: true }
);
const handleClose = () => {
emit("update:modelValue", false);
emit("close");
};
const handlePolicyClick = () => {
emit("policy-click");
};
const handleConfirmClick = () => {
emit("confirm-click");
handleClose();
};
</script>
<style lang="scss" scoped>
@import "./styles/index.scss";
</style>