|
|
@@ -49,6 +49,9 @@
|
|
|
<a-descriptions-item v-if="data.ic_count != null" label="IC次数">
|
|
|
{{ data.ic_count }}
|
|
|
</a-descriptions-item>
|
|
|
+ <a-descriptions-item v-if="data.user_lepao_count != null" label="用户当前次数">
|
|
|
+ {{ data.user_lepao_count }}
|
|
|
+ </a-descriptions-item>
|
|
|
</a-descriptions>
|
|
|
</a-card>
|
|
|
|
|
|
@@ -65,6 +68,21 @@
|
|
|
<template #title>商品详情</template>
|
|
|
<div class="goods-content" v-html="goodsContent" />
|
|
|
</a-card>
|
|
|
+
|
|
|
+ <div v-if="data.orderId" class="admin-actions">
|
|
|
+ <a-button
|
|
|
+ v-if="data.state === 2 && data.canRefund"
|
|
|
+ type="primary"
|
|
|
+ status="warning"
|
|
|
+ :loading="refundLoading"
|
|
|
+ @click="handleRefundOrder"
|
|
|
+ >
|
|
|
+ 发起退款
|
|
|
+ </a-button>
|
|
|
+ <a-tooltip v-else-if="data.state === 2 && data.refundDisabledReason" :content="data.refundDisabledReason">
|
|
|
+ <a-button status="warning" disabled>发起退款</a-button>
|
|
|
+ </a-tooltip>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
</a-skeleton>
|
|
|
@@ -74,8 +92,8 @@
|
|
|
<script setup>
|
|
|
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
|
|
import { useRoute } from 'vue-router'
|
|
|
-import { adminOrderDetail } from '@/api/order'
|
|
|
-import { Notification } from '@arco-design/web-vue'
|
|
|
+import { adminOrderDetail, adminRefundOrder } from '@/api/order'
|
|
|
+import { Notification, Message, Modal } from '@arco-design/web-vue'
|
|
|
import OrderProgressSteps from '@/components/store/OrderProgressSteps.vue'
|
|
|
import StoreDetailSkeleton from '@/components/skeleton/StoreDetailSkeleton.vue'
|
|
|
import {
|
|
|
@@ -87,6 +105,7 @@ import {
|
|
|
|
|
|
const route = useRoute()
|
|
|
const loading = ref(true)
|
|
|
+const refundLoading = ref(false)
|
|
|
const data = ref({})
|
|
|
const goodsContent = ref('')
|
|
|
const isMobile = ref(false)
|
|
|
@@ -105,14 +124,14 @@ const stepCurrent = computed(() => {
|
|
|
const state = data.value?.state
|
|
|
if (state === 0 || state === 3) return 1
|
|
|
if (state === 1) return 2
|
|
|
- if (state === 2 || state === 4) return 3
|
|
|
+ if (state === 2 || state === 4 || state === 5) return 3
|
|
|
return 1
|
|
|
})
|
|
|
|
|
|
const stepStatus = computed(() => {
|
|
|
const state = data.value?.state
|
|
|
if (state === 3 || state === 4) return 'error'
|
|
|
- if (state === 2) return 'finish'
|
|
|
+ if (state === 2 || state === 5) return 'finish'
|
|
|
return 'process'
|
|
|
})
|
|
|
|
|
|
@@ -138,6 +157,40 @@ const fetchDetail = async () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+const handleRefundOrder = () => {
|
|
|
+ const purchased = data.value?.lepao_count ?? 0
|
|
|
+ const remaining = data.value?.user_lepao_count ?? 0
|
|
|
+ Modal.confirm({
|
|
|
+ title: '管理员退款',
|
|
|
+ content: `将为用户退款 ¥${data.value?.price},并扣回 ${purchased} 次乐跑次数(用户当前剩余 ${remaining} 次)。确定继续吗?`,
|
|
|
+ okText: '确认退款',
|
|
|
+ cancelText: '取消',
|
|
|
+ okButtonProps: { status: 'warning' },
|
|
|
+ onOk: async () => {
|
|
|
+ try {
|
|
|
+ refundLoading.value = true
|
|
|
+ const res = await adminRefundOrder({ orderId: route.params.orderId })
|
|
|
+ if (!res || res.code !== 0) {
|
|
|
+ Notification.error({
|
|
|
+ title: '退款失败',
|
|
|
+ content: res?.msg ?? '请稍后再试'
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ Message.success(res.msg || '退款成功')
|
|
|
+ await fetchDetail()
|
|
|
+ } catch (error) {
|
|
|
+ Notification.error({
|
|
|
+ title: '退款失败',
|
|
|
+ content: error.message || '请稍后再试'
|
|
|
+ })
|
|
|
+ } finally {
|
|
|
+ refundLoading.value = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
onMounted(async () => {
|
|
|
const syncMobile = () => {
|
|
|
isMobile.value = window.innerWidth <= 768
|
|
|
@@ -196,6 +249,12 @@ onUnmounted(() => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+.admin-actions {
|
|
|
+ display: flex;
|
|
|
+ gap: 12px;
|
|
|
+ flex-wrap: wrap;
|
|
|
+}
|
|
|
+
|
|
|
@media (max-width: 768px) {
|
|
|
.admin-order-detail {
|
|
|
padding: 0 12px 16px;
|