orderDetail.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. <template>
  2. <div class="admin-order-detail">
  3. <Breadcrumb />
  4. <a-spin :loading="loading" style="width: 100%">
  5. <div v-if="!loading && data.orderId" class="detail-grid">
  6. <a-card :bordered="false" class="detail-card detail-card--status">
  7. <template #title>订单进度</template>
  8. <a-steps :current="stepCurrent" :status="stepStatus" label-placement="vertical">
  9. <a-step description="用户提交订单">待支付</a-step>
  10. <a-step description="支付成功,系统处理">待处理</a-step>
  11. <a-step description="权益已发放">已完成</a-step>
  12. </a-steps>
  13. <div class="state-center">
  14. <a-tag :color="stateMeta.color" size="large">{{ stateMeta.label }}</a-tag>
  15. </div>
  16. </a-card>
  17. <a-card :bordered="false" class="detail-card">
  18. <template #title>订单信息</template>
  19. <a-descriptions :column="{ xs: 1, sm: 2 }" bordered>
  20. <a-descriptions-item label="订单号">{{ data.orderId }}</a-descriptions-item>
  21. <a-descriptions-item label="商品">{{ data.name || '-' }}</a-descriptions-item>
  22. <a-descriptions-item v-if="data.original_price" label="商品原价">
  23. ¥{{ data.original_price }}
  24. </a-descriptions-item>
  25. <a-descriptions-item v-if="data.coupon_code" label="优惠码">
  26. {{ data.coupon_code }}
  27. </a-descriptions-item>
  28. <a-descriptions-item v-if="data.discount_amount > 0" label="优惠减免">
  29. ¥{{ data.discount_amount }}
  30. </a-descriptions-item>
  31. <a-descriptions-item label="实付金额">
  32. <span class="price">¥{{ data.price }}</span>
  33. </a-descriptions-item>
  34. <a-descriptions-item label="支付方式">{{ getPayTypeLabel(data.pay_type) }}</a-descriptions-item>
  35. <a-descriptions-item label="下单时间">{{ formatStoreTimeFull(data.create_time) }}</a-descriptions-item>
  36. <a-descriptions-item label="支付时间">{{ formatStoreTimeFull(data.pay_time) }}</a-descriptions-item>
  37. <a-descriptions-item v-if="data.pay_id" label="支付平台单号" :span="2">
  38. {{ data.pay_id }}
  39. </a-descriptions-item>
  40. <a-descriptions-item v-if="data.lepao_count != null" label="乐跑次数">
  41. {{ data.lepao_count }}
  42. </a-descriptions-item>
  43. <a-descriptions-item v-if="data.ic_count != null" label="IC次数">
  44. {{ data.ic_count }}
  45. </a-descriptions-item>
  46. </a-descriptions>
  47. </a-card>
  48. <a-card :bordered="false" class="detail-card">
  49. <template #title>买家信息</template>
  50. <a-descriptions :column="{ xs: 1, sm: 2 }" bordered>
  51. <a-descriptions-item label="用户名">{{ data.username || '-' }}</a-descriptions-item>
  52. <a-descriptions-item label="邮箱">{{ data.user_email || '-' }}</a-descriptions-item>
  53. <a-descriptions-item label="用户 UUID" :span="2">{{ data.create_user || '-' }}</a-descriptions-item>
  54. </a-descriptions>
  55. </a-card>
  56. <a-card v-if="goodsContent" :bordered="false" class="detail-card detail-card--full">
  57. <template #title>商品详情</template>
  58. <div class="goods-content" v-html="goodsContent" />
  59. </a-card>
  60. </div>
  61. </a-spin>
  62. </div>
  63. </template>
  64. <script setup>
  65. import { ref, computed, onMounted } from 'vue'
  66. import { useRoute } from 'vue-router'
  67. import { adminOrderDetail } from '@/api/order'
  68. import { Notification } from '@arco-design/web-vue'
  69. import {
  70. formatStoreTimeFull,
  71. getPayTypeLabel,
  72. getOrderStateMeta,
  73. decodeGoodsContent
  74. } from '@/utils/storeFormat'
  75. const route = useRoute()
  76. const loading = ref(true)
  77. const data = ref({})
  78. const goodsContent = ref('')
  79. const stateMeta = computed(() => getOrderStateMeta(data.value?.state ?? -1))
  80. const stepCurrent = computed(() => {
  81. const state = data.value?.state
  82. if (state === 0 || state === 3) return 1
  83. if (state === 1) return 2
  84. if (state === 2 || state === 4) return 3
  85. return 1
  86. })
  87. const stepStatus = computed(() => {
  88. const state = data.value?.state
  89. if (state === 3 || state === 4) return 'error'
  90. if (state === 2) return 'finish'
  91. return 'process'
  92. })
  93. const fetchDetail = async () => {
  94. try {
  95. loading.value = true
  96. const res = await adminOrderDetail({ orderId: route.params.orderId })
  97. if (!res || res.code !== 0) {
  98. return Notification.error({
  99. title: '获取订单详情失败',
  100. content: res?.msg ?? '请稍后再试'
  101. })
  102. }
  103. data.value = res.data || {}
  104. goodsContent.value = decodeGoodsContent(res.data?.content)
  105. } catch (error) {
  106. Notification.error({
  107. title: '获取订单详情失败',
  108. content: error.message || '请稍后再试'
  109. })
  110. } finally {
  111. loading.value = false
  112. }
  113. }
  114. onMounted(fetchDetail)
  115. </script>
  116. <style scoped lang="less">
  117. .admin-order-detail {
  118. padding: 0 20px 20px;
  119. }
  120. .detail-grid {
  121. display: grid;
  122. grid-template-columns: 1fr;
  123. gap: 16px;
  124. @media (min-width: 960px) {
  125. grid-template-columns: 1fr 1fr;
  126. .detail-card--status,
  127. .detail-card--full {
  128. grid-column: 1 / -1;
  129. }
  130. }
  131. }
  132. .detail-card {
  133. border-radius: 12px;
  134. border: 1px solid var(--color-border-2);
  135. }
  136. .state-center {
  137. margin-top: 20px;
  138. text-align: center;
  139. }
  140. .price {
  141. font-weight: 700;
  142. color: #e85d04;
  143. }
  144. .goods-content {
  145. line-height: 1.75;
  146. :deep(img) {
  147. max-width: 100%;
  148. }
  149. }
  150. </style>