fix(admin): fix refund dialog amount for REFUND_REQUESTED, improve button styles

- Don't treat refund_amount as "already refunded" in REFUND_REQUESTED status
  (it's the requested amount, not actually refunded)
- Pre-fill refund amount with user's requested amount
- Show "already refunded" only for PARTIALLY_REFUNDED/REFUNDED orders
- Change action buttons from stacked icon+text to compact inline style
This commit is contained in:
erio
2026-04-09 22:07:06 +08:00
parent 66cd16fce3
commit e25e7b3f2d
2 changed files with 32 additions and 23 deletions
@@ -37,9 +37,9 @@
<span class="text-gray-500 dark:text-gray-400">{{ t('payment.orders.amount') }}</span>
<span class="font-medium text-gray-900 dark:text-white">${{ order?.pay_amount?.toFixed(2) }}</span>
</div>
<div v-if="order?.refund_amount" class="mt-1 flex justify-between text-sm">
<div v-if="actuallyRefunded > 0" class="mt-1 flex justify-between text-sm">
<span class="text-gray-500 dark:text-gray-400">{{ t('payment.admin.alreadyRefunded') }}</span>
<span class="font-medium text-red-600 dark:text-red-400">${{ order.refund_amount.toFixed(2) }}</span>
<span class="font-medium text-red-600 dark:text-red-400">${{ actuallyRefunded.toFixed(2) }}</span>
</div>
</div>
@@ -188,9 +188,18 @@ const form = reactive({
force: false,
})
// In REFUND_REQUESTED status, refund_amount is the REQUESTED amount, not actually refunded.
// Only PARTIALLY_REFUNDED / REFUNDED have real refund amounts.
const actuallyRefunded = computed(() => {
if (!props.order) return 0
const s = props.order.status
if (s === 'PARTIALLY_REFUNDED' || s === 'REFUNDED') return props.order.refund_amount || 0
return 0
})
const maxRefundable = computed(() => {
if (!props.order) return 0
return props.order.pay_amount - (props.order.refund_amount || 0)
return props.order.pay_amount - actuallyRefunded.value
})
const balanceInsufficient = computed(() => {
@@ -200,7 +209,12 @@ const balanceInsufficient = computed(() => {
watch(() => props.show, (val) => {
if (val && props.order) {
form.amount = maxRefundable.value
// For REFUND_REQUESTED, pre-fill with the requested amount
if (props.order.status === 'REFUND_REQUESTED' && props.order.refund_amount) {
form.amount = props.order.refund_amount
} else {
form.amount = maxRefundable.value
}
form.reason = props.order.refund_request_reason || ''
form.deduct_balance = true
form.force = false
@@ -41,38 +41,33 @@
<span class="text-xs text-gray-500 dark:text-gray-400">{{ formatDateTime(value) }}</span>
</template>
<template #cell-actions="{ row }">
<div class="flex items-center gap-2">
<button @click="showOrderDetail(row)" class="flex flex-col items-center gap-0.5 rounded-lg p-1.5 text-gray-500 transition-colors hover:bg-gray-50 hover:text-gray-700 dark:hover:bg-gray-800/50 dark:hover:text-gray-300">
<div class="flex items-center gap-1">
<button @click="showOrderDetail(row)" class="inline-flex items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-dark-600">
<Icon name="eye" size="sm" />
<span class="text-xs">{{ t('common.view') }}</span>
{{ t('common.view') }}
</button>
<button v-if="row.status === 'PENDING'" @click="handleCancelOrder(row)" class="flex flex-col items-center gap-0.5 rounded-lg p-1.5 text-gray-500 transition-colors hover:bg-yellow-50 hover:text-yellow-600 dark:hover:bg-yellow-900/20 dark:hover:text-yellow-400">
<button v-if="row.status === 'PENDING'" @click="handleCancelOrder(row)" class="inline-flex items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-yellow-600 hover:bg-yellow-50 dark:text-yellow-400 dark:hover:bg-yellow-900/20">
<Icon name="x" size="sm" />
<span class="text-xs">{{ t('payment.orders.cancel') }}</span>
{{ t('payment.orders.cancel') }}
</button>
<button v-if="row.status === 'FAILED'" @click="handleRetryOrder(row)" class="flex flex-col items-center gap-0.5 rounded-lg p-1.5 text-gray-500 transition-colors hover:bg-blue-50 hover:text-blue-600 dark:hover:bg-blue-900/20 dark:hover:text-blue-400">
<button v-if="row.status === 'FAILED'" @click="handleRetryOrder(row)" class="inline-flex items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-blue-600 hover:bg-blue-50 dark:text-blue-400 dark:hover:bg-blue-900/20">
<Icon name="refresh" size="sm" />
<span class="text-xs">{{ t('payment.admin.retry') }}</span>
{{ t('payment.admin.retry') }}
</button>
<!-- REFUND_REQUESTED: show requested amount badge + approve button -->
<template v-if="row.status === 'REFUND_REQUESTED'">
<span v-if="row.refund_amount" class="inline-flex items-center rounded-full bg-purple-100 px-2 py-0.5 text-xs font-medium text-purple-700 dark:bg-purple-900/30 dark:text-purple-300">
${{ row.refund_amount.toFixed(2) }}
</span>
<button @click="openRefundDialog(row)" class="flex flex-col items-center gap-0.5 rounded-lg p-1.5 text-gray-500 transition-colors hover:bg-purple-50 hover:text-purple-600 dark:hover:bg-purple-900/20 dark:hover:text-purple-400">
<span v-if="row.refund_amount" class="rounded-full bg-purple-100 px-1.5 py-0.5 text-xs font-medium text-purple-700 dark:bg-purple-900/30 dark:text-purple-300">${{ row.refund_amount.toFixed(2) }}</span>
<button @click="openRefundDialog(row)" class="inline-flex items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-purple-600 hover:bg-purple-50 dark:text-purple-400 dark:hover:bg-purple-900/20">
<Icon name="check" size="sm" />
<span class="text-xs">{{ t('payment.admin.approveRefund') }}</span>
{{ t('payment.admin.approveRefund') }}
</button>
</template>
<!-- REFUND_FAILED: show retry refund button -->
<button v-else-if="row.status === 'REFUND_FAILED'" @click="openRefundDialog(row)" class="flex flex-col items-center gap-0.5 rounded-lg p-1.5 text-gray-500 transition-colors hover:bg-purple-50 hover:text-purple-600 dark:hover:bg-purple-900/20 dark:hover:text-purple-400">
<button v-else-if="row.status === 'REFUND_FAILED'" @click="openRefundDialog(row)" class="inline-flex items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-purple-600 hover:bg-purple-50 dark:text-purple-400 dark:hover:bg-purple-900/20">
<Icon name="refresh" size="sm" />
<span class="text-xs">{{ t('payment.admin.retryRefund') }}</span>
{{ t('payment.admin.retryRefund') }}
</button>
<!-- COMPLETED / PARTIALLY_REFUNDED: show refund button -->
<button v-else-if="row.status === 'COMPLETED' || row.status === 'PARTIALLY_REFUNDED'" @click="openRefundDialog(row)" class="flex flex-col items-center gap-0.5 rounded-lg p-1.5 text-gray-500 transition-colors hover:bg-red-50 hover:text-red-600 dark:hover:bg-red-900/20 dark:hover:text-red-400">
<button v-else-if="row.status === 'COMPLETED' || row.status === 'PARTIALLY_REFUNDED'" @click="openRefundDialog(row)" class="inline-flex items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-red-600 hover:bg-red-50 dark:text-red-400 dark:hover:bg-red-900/20">
<Icon name="dollar" size="sm" />
<span class="text-xs">{{ t('payment.admin.refund') }}</span>
{{ t('payment.admin.refund') }}
</button>
</div>
</template>