|
@@ -165,7 +165,7 @@
|
|
|
<el-table-column prop="refund_reason" label="退款原因" min-width="160" show-overflow-tooltip>
|
|
<el-table-column prop="refund_reason" label="退款原因" min-width="160" show-overflow-tooltip>
|
|
|
<template #default="{ row }">{{ row.refund_reason || "-" }}</template>
|
|
<template #default="{ row }">{{ row.refund_reason || "-" }}</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
- <el-table-column label="操作" width="150" fixed="right">
|
|
|
|
|
|
|
+ <el-table-column label="操作" width="200" fixed="right">
|
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
|
<el-button
|
|
<el-button
|
|
|
v-hasPerm="['module_payment:har:order:detail']"
|
|
v-hasPerm="['module_payment:har:order:detail']"
|
|
@@ -183,6 +183,20 @@
|
|
|
>
|
|
>
|
|
|
同步
|
|
同步
|
|
|
</el-button>
|
|
</el-button>
|
|
|
|
|
+ <!--
|
|
|
|
|
+ 只在「1 支付成功」出现:上游只受理从已支付发起的退款,其余状态(含 4 退款中、
|
|
|
|
|
+ 2 退款成功)点了必然是 400 —— 与其给一个永远失败的按钮,不如不给。
|
|
|
|
|
+ -->
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ v-if="row.trade_status === HAR_ORDER_STATUS_PAID"
|
|
|
|
|
+ v-hasPerm="['module_payment:har:order:refund']"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ type="danger"
|
|
|
|
|
+ :loading="refundingId === row.id"
|
|
|
|
|
+ @click="handleRefund(row)"
|
|
|
|
|
+ >
|
|
|
|
|
+ 退款
|
|
|
|
|
+ </el-button>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
</el-table>
|
|
</el-table>
|
|
@@ -427,6 +441,15 @@
|
|
|
>
|
|
>
|
|
|
同步上游状态
|
|
同步上游状态
|
|
|
</el-button>
|
|
</el-button>
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ v-if="detail?.trade_status === HAR_ORDER_STATUS_PAID"
|
|
|
|
|
+ v-hasPerm="['module_payment:har:order:refund']"
|
|
|
|
|
+ type="danger"
|
|
|
|
|
+ :loading="refundingId === detail?.id"
|
|
|
|
|
+ @click="detail && handleRefund(detail)"
|
|
|
|
|
+ >
|
|
|
|
|
+ 退款
|
|
|
|
|
+ </el-button>
|
|
|
<el-button @click="detailVisible = false">关闭</el-button>
|
|
<el-button @click="detailVisible = false">关闭</el-button>
|
|
|
</template>
|
|
</template>
|
|
|
</el-dialog>
|
|
</el-dialog>
|
|
@@ -435,11 +458,12 @@
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
import { onMounted, reactive, ref } from "vue";
|
|
import { onMounted, reactive, ref } from "vue";
|
|
|
-import { ElMessage, type FormInstance, type FormRules } from "element-plus";
|
|
|
|
|
|
|
+import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from "element-plus";
|
|
|
import dayjs from "dayjs";
|
|
import dayjs from "dayjs";
|
|
|
import HarAPI, {
|
|
import HarAPI, {
|
|
|
HAR_BIZ_UN_STAGE,
|
|
HAR_BIZ_UN_STAGE,
|
|
|
HAR_NOTIFY_STATUS_TEXT,
|
|
HAR_NOTIFY_STATUS_TEXT,
|
|
|
|
|
+ HAR_ORDER_STATUS_PAID,
|
|
|
HAR_TRADE_STATUS_TAG,
|
|
HAR_TRADE_STATUS_TAG,
|
|
|
HAR_TRADE_STATUS_TEXT,
|
|
HAR_TRADE_STATUS_TEXT,
|
|
|
HAR_TRADE_TYPE_OPTIONS,
|
|
HAR_TRADE_TYPE_OPTIONS,
|
|
@@ -463,6 +487,7 @@ const pageNo = ref(1);
|
|
|
const pageSize = ref(20);
|
|
const pageSize = ref(20);
|
|
|
const loading = ref(false);
|
|
const loading = ref(false);
|
|
|
const syncingId = ref<string | undefined>();
|
|
const syncingId = ref<string | undefined>();
|
|
|
|
|
+const refundingId = ref<string | undefined>();
|
|
|
|
|
|
|
|
const createVisible = ref(false);
|
|
const createVisible = ref(false);
|
|
|
const saving = ref(false);
|
|
const saving = ref(false);
|
|
@@ -675,6 +700,53 @@ async function handleSync(row: HarOrderVO) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 退款(**全额**,动钱)。
|
|
|
|
|
+ *
|
|
|
|
|
+ * 确认框里三件事必须写出来,少一件这个按钮就是在误导操作员:
|
|
|
|
|
+ * ① 金额不可选 —— 上游退款 biz 只有单号、没有金额字段,本通道不存在部分退款;
|
|
|
|
|
+ * ② 提交成功 ≠ 到账 —— 拿到的是「4 退款中」,到账以收敛成「2 退款成功」为准(提示语照此写);
|
|
|
|
|
+ * ③ 原因选填,但留空由服务端补默认值(上游对空原因是**整笔拒**,所以这里不设 inputPattern
|
|
|
|
|
+ * 逼人填,只在占位符里说明)。
|
|
|
|
|
+ *
|
|
|
|
|
+ * 不做 HTML 拼接:单号走文本插值,不用 dangerouslyUseHTMLString。
|
|
|
|
|
+ */
|
|
|
|
|
+async function handleRefund(row: HarOrderVO) {
|
|
|
|
|
+ let reason = "";
|
|
|
|
|
+ try {
|
|
|
|
|
+ const { value } = await ElMessageBox.prompt(
|
|
|
|
|
+ `订单 ${row.order_no} 将按 ¥${row.price} 发起全额退款,金额不可修改;` +
|
|
|
|
|
+ "提交成功只代表上游已受理,到账以状态变为「退款成功」为准。",
|
|
|
|
|
+ "确认退款",
|
|
|
|
|
+ {
|
|
|
|
|
+ confirmButtonText: "确认全额退款",
|
|
|
|
|
+ cancelButtonText: "取消",
|
|
|
|
|
+ inputPlaceholder: "退款原因(选填),留空将使用默认原因",
|
|
|
|
|
+ }
|
|
|
|
|
+ );
|
|
|
|
|
+ reason = value ?? "";
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ return; // 取消(ElMessageBox 以 "cancel" reject),不发请求
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ refundingId.value = row.id;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await HarAPI.orderRefund(row.id as string, reason);
|
|
|
|
|
+ const updated = res.data.data;
|
|
|
|
|
+ // 照实说「已受理」:这一步之后订单停在「4 退款中」,不是「2 退款成功」
|
|
|
|
|
+ ElMessage.success(
|
|
|
|
|
+ `退款已受理(${HAR_TRADE_STATUS_TEXT[updated.trade_status] || updated.trade_status}),` +
|
|
|
|
|
+ "到账以状态变为「退款成功」为准"
|
|
|
|
|
+ );
|
|
|
|
|
+ if (detailVisible.value && detail.value?.id === row.id) {
|
|
|
|
|
+ detail.value = updated;
|
|
|
|
|
+ }
|
|
|
|
|
+ load();
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ refundingId.value = undefined;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
function openPayUrl(url?: string) {
|
|
function openPayUrl(url?: string) {
|
|
|
if (!url) {
|
|
if (!url) {
|
|
|
return;
|
|
return;
|