422 lines
16 KiB
Vue
422 lines
16 KiB
Vue
<template>
|
||
<el-dialog title="统一退款" :visible.sync="visible" width="900px" @close="handleClose">
|
||
<el-form ref="refundForm" :model="refundForm" label-width="100px">
|
||
<div class="refund-container">
|
||
<!-- 支付信息展示 -->
|
||
<div class="payment-info" v-if="paymentData">
|
||
<h4>支付信息</h4>
|
||
<el-row :gutter="20">
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<label>微信支付:</label>
|
||
<span class="amount">¥{{ paymentData.wechatAmount || '0.00' }}</span>
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<label>余额支付:</label>
|
||
<span class="amount">¥{{ paymentData.balanceAmount || '0.00' }}</span>
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<label>购物金:</label>
|
||
<span class="amount">¥{{ paymentData.shoppingGoldAmount || '0.00' }}</span>
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row :gutter="20">
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<label>服务金:</label>
|
||
<span class="amount">¥{{ paymentData.serviceGoldAmount || '0.00' }}</span>
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<label>会员优惠:</label>
|
||
<span class="amount">¥{{ paymentData.memberDiscountAmount || '0.00' }}</span>
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<label>优惠券抵扣:</label>
|
||
<span class="amount">¥{{ paymentData.couponAmount || '0.00' }}</span>
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
<div class="total-amount">
|
||
<label>总支付金额:</label>
|
||
<span class="amount total">¥{{ totalPaymentAmount }}</span>
|
||
</div>
|
||
|
||
<!-- 退款历史信息 -->
|
||
<div class="refund-history" v-if="refundHistory && refundHistory.length > 0">
|
||
<h5>退款历史</h5>
|
||
<div class="history-item" v-for="(item, index) in refundHistory" :key="index">
|
||
<span class="history-time">{{ formatTime(item.refundTime) }}</span>
|
||
<span class="history-amount">¥{{ item.totalRefund }}</span>
|
||
<span class="history-desc">{{ item.name }}</span>
|
||
</div>
|
||
<div class="history-summary">
|
||
<span>累计已退款:¥{{ totalRefundedAmount }}</span>
|
||
<span class="remaining">剩余可退款:¥{{ remainingRefundableAmount }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 退款金额输入 -->
|
||
<div class="refund-input">
|
||
<h4>本次退款金额</h4>
|
||
<el-row :gutter="20">
|
||
<el-col :span="8">
|
||
<el-form-item label="微信退款:">
|
||
<el-input
|
||
v-model="refundForm.wechatRefund"
|
||
type="number"
|
||
placeholder="0.00"
|
||
min="0"
|
||
step="0.01"
|
||
@input="calculateTotalRefund"
|
||
>
|
||
<template slot="prepend">¥</template>
|
||
</el-input>
|
||
<div class="input-tip">最大可退:¥{{ paymentData.wechatAmount || '0.00' }}</div>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item label="余额退款:">
|
||
<el-input
|
||
v-model="refundForm.balanceRefund"
|
||
type="number"
|
||
placeholder="0.00"
|
||
min="0"
|
||
step="0.01"
|
||
@input="calculateTotalRefund"
|
||
>
|
||
<template slot="prepend">¥</template>
|
||
</el-input>
|
||
<div class="input-tip">最大可退:¥{{ paymentData.balanceAmount || '0.00' }}</div>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item label="购物金退款:">
|
||
<el-input
|
||
v-model="refundForm.shoppingGoldRefund"
|
||
type="number"
|
||
placeholder="0.00"
|
||
min="0"
|
||
step="0.01"
|
||
@input="calculateTotalRefund"
|
||
>
|
||
<template slot="prepend">¥</template>
|
||
</el-input>
|
||
<div class="input-tip">最大可退:¥{{ paymentData.shoppingGoldAmount || '0.00' }}</div>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row :gutter="20">
|
||
<el-col :span="8">
|
||
<el-form-item label="服务金退款:">
|
||
<el-input
|
||
v-model="refundForm.serviceGoldRefund"
|
||
type="number"
|
||
placeholder="0.00"
|
||
min="0"
|
||
step="0.01"
|
||
@input="calculateTotalRefund"
|
||
>
|
||
<template slot="prepend">¥</template>
|
||
</el-input>
|
||
<div class="input-tip">最大可退:¥{{ paymentData.serviceGoldAmount || '0.00' }}</div>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item label="会员优惠退款:">
|
||
<el-input
|
||
v-model="refundForm.memberDiscountRefund"
|
||
type="number"
|
||
placeholder="0.00"
|
||
min="0"
|
||
step="0.01"
|
||
@input="calculateTotalRefund"
|
||
>
|
||
<template slot="prepend">¥</template>
|
||
</el-input>
|
||
<div class="input-tip">最大可退:¥{{ paymentData.memberDiscountAmount || '0.00' }}</div>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item label="优惠券退款:">
|
||
<el-input
|
||
v-model="refundForm.couponRefund"
|
||
type="number"
|
||
placeholder="0.00"
|
||
min="0"
|
||
step="0.01"
|
||
@input="calculateTotalRefund"
|
||
>
|
||
<template slot="prepend">¥</template>
|
||
</el-input>
|
||
<div class="input-tip">最大可退:¥{{ paymentData.couponAmount || '0.00' }}</div>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<!-- 总退款金额显示 -->
|
||
<div class="total-refund">
|
||
<label>本次退款金额:</label>
|
||
<span class="amount refund">¥{{ totalRefundAmount }}</span>
|
||
</div>
|
||
|
||
<!-- 退款验证提示 -->
|
||
<div class="refund-validation" v-if="totalRefundAmount > 0">
|
||
<el-alert
|
||
:title="validationMessage"
|
||
:type="validationType"
|
||
show-icon
|
||
:closable="false"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 退款备注 -->
|
||
<div class="refund-remark">
|
||
<el-form-item label="退款备注:">
|
||
<el-input
|
||
v-model="refundForm.refundRemark"
|
||
type="textarea"
|
||
:rows="3"
|
||
placeholder="请输入退款备注信息"
|
||
maxlength="200"
|
||
show-word-limit
|
||
/>
|
||
</el-form-item>
|
||
</div>
|
||
</div>
|
||
</el-form>
|
||
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button @click="handleClose">取消</el-button>
|
||
<el-button type="primary" @click="handleConfirm" :loading="loading" :disabled="!canRefund">确认退款</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
</template>
|
||
|
||
<script>
|
||
import { unifiedRefund } from "@/api/system/UsersPayBefor"
|
||
|
||
export default {
|
||
name: "UnifiedRefundDialog",
|
||
props: {
|
||
visible: { type: Boolean, default: false },
|
||
orderId: { type: String, default: "" },
|
||
paymentData: { type: Object, default: () => ({}) }
|
||
},
|
||
data() {
|
||
return {
|
||
loading: false,
|
||
refundForm: {
|
||
wechatRefund: "",
|
||
balanceRefund: "",
|
||
shoppingGoldRefund: "",
|
||
serviceGoldRefund: "",
|
||
memberDiscountRefund: "",
|
||
couponRefund: "",
|
||
refundRemark: ""
|
||
},
|
||
totalRefundAmount: "0.00",
|
||
refundHistory: [], // 退款历史
|
||
totalRefundedAmount: "0.00", // 累计已退款
|
||
remainingRefundableAmount: "0.00" // 剩余可退款
|
||
}
|
||
},
|
||
computed: {
|
||
totalPaymentAmount() {
|
||
if (!this.paymentData) return "0.00";
|
||
const total = (this.paymentData.wechatAmount || 0) + (this.paymentData.balanceAmount || 0) +
|
||
(this.paymentData.shoppingGoldAmount || 0) + (this.paymentData.serviceGoldAmount || 0) +
|
||
(this.paymentData.memberDiscountAmount || 0) + (this.paymentData.couponAmount || 0);
|
||
return total.toFixed(2);
|
||
},
|
||
|
||
canRefund() {
|
||
return parseFloat(this.totalRefundAmount) > 0 && parseFloat(this.totalRefundAmount) <= parseFloat(this.remainingRefundableAmount);
|
||
},
|
||
|
||
validationMessage() {
|
||
const totalRefund = parseFloat(this.totalRefundAmount);
|
||
const remaining = parseFloat(this.remainingRefundableAmount);
|
||
|
||
if (totalRefund > remaining) {
|
||
return `退款金额超过剩余可退款金额,最多可退:¥${this.remainingRefundableAmount}`;
|
||
} else if (totalRefund > 0) {
|
||
return `退款后将剩余可退款:¥${(remaining - totalRefund).toFixed(2)}`;
|
||
}
|
||
return "";
|
||
},
|
||
|
||
validationType() {
|
||
const totalRefund = parseFloat(this.totalRefundAmount);
|
||
const remaining = parseFloat(this.remainingRefundableAmount);
|
||
return totalRefund > remaining ? "error" : "success";
|
||
}
|
||
},
|
||
watch: {
|
||
visible(newVal) {
|
||
if (newVal) {
|
||
this.initForm();
|
||
this.loadRefundHistory();
|
||
}
|
||
}
|
||
},
|
||
methods: {
|
||
initForm() {
|
||
// 初始化表单,设置最大退款金额
|
||
this.refundForm.wechatRefund = "";
|
||
this.refundForm.balanceRefund = "";
|
||
this.refundForm.shoppingGoldRefund = "";
|
||
this.refundForm.serviceGoldRefund = "";
|
||
this.refundForm.memberDiscountRefund = "";
|
||
this.refundForm.couponRefund = "";
|
||
this.refundForm.refundRemark = "";
|
||
this.calculateTotalRefund();
|
||
},
|
||
|
||
async loadRefundHistory() {
|
||
try {
|
||
// 这里可以调用API获取退款历史
|
||
// const response = await getRefundHistory(this.orderId);
|
||
// this.refundHistory = response.data || [];
|
||
|
||
// 模拟数据,实际应该从API获取
|
||
this.refundHistory = [];
|
||
this.totalRefundedAmount = "0.00";
|
||
this.remainingRefundableAmount = this.totalPaymentAmount;
|
||
} catch (error) {
|
||
console.error('获取退款历史失败:', error);
|
||
}
|
||
},
|
||
|
||
calculateTotalRefund() {
|
||
const total = (parseFloat(this.refundForm.wechatRefund) || 0) + (parseFloat(this.refundForm.balanceRefund) || 0) +
|
||
(parseFloat(this.refundForm.shoppingGoldRefund) || 0) + (parseFloat(this.refundForm.serviceGoldRefund) || 0) +
|
||
(parseFloat(this.refundForm.memberDiscountRefund) || 0) + (parseFloat(this.refundForm.couponRefund) || 0);
|
||
this.totalRefundAmount = total.toFixed(2);
|
||
},
|
||
|
||
validateRefundAmount() {
|
||
const totalRefund = parseFloat(this.totalRefundAmount);
|
||
const remaining = parseFloat(this.remainingRefundableAmount);
|
||
|
||
if (totalRefund <= 0) {
|
||
this.$message.error("退款金额必须大于0");
|
||
return false;
|
||
}
|
||
|
||
if (totalRefund > remaining) {
|
||
this.$message.error(`退款金额不能超过剩余可退款金额,最多可退:¥${this.remainingRefundableAmount}`);
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
},
|
||
|
||
async handleConfirm() {
|
||
if (!this.validateRefundAmount()) return;
|
||
|
||
this.loading = true;
|
||
|
||
try {
|
||
const params = {
|
||
orderId: this.orderId,
|
||
wechatRefund: this.refundForm.wechatRefund || "0",
|
||
balanceRefund: this.refundForm.balanceRefund || "0",
|
||
shoppingGoldRefund: this.refundForm.shoppingGoldRefund || "0",
|
||
serviceGoldRefund: this.refundForm.serviceGoldRefund || "0",
|
||
memberDiscountRefund: this.refundForm.memberDiscountRefund || "0",
|
||
couponRefund: this.refundForm.couponRefund || "0",
|
||
refundRemark: this.refundForm.refundRemark
|
||
};
|
||
|
||
const response = await unifiedRefund(params);
|
||
|
||
if (response.code === 200) {
|
||
this.$message.success("退款成功");
|
||
this.$emit("success", response.data);
|
||
this.handleClose();
|
||
} else {
|
||
this.$message.error(response.msg || "退款失败");
|
||
}
|
||
} catch (error) {
|
||
console.error("退款失败:", error);
|
||
this.$message.error("退款失败,请重试");
|
||
} finally {
|
||
this.loading = false;
|
||
}
|
||
},
|
||
|
||
handleClose() {
|
||
this.$emit("update:visible", false);
|
||
this.resetForm();
|
||
},
|
||
|
||
resetForm() {
|
||
this.refundForm = {
|
||
wechatRefund: "",
|
||
balanceRefund: "",
|
||
shoppingGoldRefund: "",
|
||
serviceGoldRefund: "",
|
||
memberDiscountRefund: "",
|
||
couponRefund: "",
|
||
refundRemark: ""
|
||
};
|
||
this.totalRefundAmount = "0.00";
|
||
this.loading = false;
|
||
},
|
||
|
||
formatTime(timeStr) {
|
||
if (!timeStr) return '';
|
||
const date = new Date(timeStr);
|
||
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.refund-container { padding: 20px 0; }
|
||
.payment-info { background-color: #f8f9fa; padding: 20px; border-radius: 8px; margin-bottom: 20px; border: 1px solid #e9ecef; }
|
||
.payment-info h4 { margin: 0 0 15px 0; color: #303133; font-size: 16px; font-weight: 600; }
|
||
.info-item { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; padding: 8px 0; }
|
||
.info-item label { font-weight: 500; color: #606266; min-width: 80px; }
|
||
.amount { font-weight: 600; color: #E6A23C; }
|
||
.amount.total { font-size: 18px; color: #409EFF; }
|
||
.total-amount { text-align: center; margin-top: 15px; padding-top: 15px; border-top: 1px solid #e9ecef; }
|
||
.total-amount label { font-weight: 600; color: #303133; margin-right: 10px; }
|
||
|
||
/* 退款历史样式 */
|
||
.refund-history { margin-top: 20px; padding-top: 20px; border-top: 1px solid #e9ecef; }
|
||
.refund-history h5 { margin: 0 0 15px 0; color: #303133; font-size: 14px; font-weight: 600; }
|
||
.history-item { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; padding: 5px 0; font-size: 12px; }
|
||
.history-time { color: #909399; min-width: 120px; }
|
||
.history-amount { color: #F56C6C; font-weight: 600; min-width: 80px; text-align: right; }
|
||
.history-desc { color: #606266; flex: 1; margin-left: 10px; }
|
||
.history-summary { display: flex; justify-content: space-between; margin-top: 10px; padding-top: 10px; border-top: 1px solid #e9ecef; font-weight: 600; }
|
||
.remaining { color: #409EFF; }
|
||
|
||
.refund-input { background-color: #fff; padding: 20px; border-radius: 8px; border: 1px solid #e9ecef; margin-bottom: 20px; }
|
||
.refund-input h4 { margin: 0 0 15px 0; color: #303133; font-size: 16px; font-weight: 600; }
|
||
.total-refund { text-align: center; margin-top: 20px; padding-top: 20px; border-top: 1px solid #e9ecef; }
|
||
.total-refund label { font-weight: 600; color: #303133; margin-right: 10px; }
|
||
.amount.refund { font-size: 20px; color: #F56C6C; font-weight: bold; }
|
||
|
||
.input-tip { font-size: 11px; color: #909399; margin-top: 2px; }
|
||
|
||
.refund-validation { margin-top: 15px; }
|
||
|
||
.refund-remark { background-color: #fff; padding: 20px; border-radius: 8px; border: 1px solid #e9ecef; }
|
||
.dialog-footer { text-align: right; }
|
||
.el-form-item { margin-bottom: 15px; }
|
||
.el-input-group__prepend { background-color: #f5f7fa; color: #909399; font-weight: 500; }
|
||
</style> |