refund.vue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. <script setup>
  2. import { ref, onMounted } from 'vue'
  3. import { onShow } from '@dcloudio/uni-app'
  4. import { useUserStore } from '@/stores/user'
  5. import { request, parseResponseJson } from '@/utils/request'
  6. import { API_URL } from '@/config/api'
  7. import { formatYuan } from '@/utils/format'
  8. import SqCopyBtn from '@/components/sq-copy-btn.vue'
  9. const userStore = useUserStore()
  10. const list = ref([])
  11. const loading = ref(false)
  12. const statusText = {
  13. pending: '处理中',
  14. success: '成功',
  15. failed: '失败',
  16. cancelled: '已取消'
  17. }
  18. async function load() {
  19. loading.value = true
  20. try {
  21. const res = await request({
  22. url: API_URL.CLIENT_REFUNDS,
  23. method: 'GET',
  24. data: { page: 1, pageSize: 50 }
  25. })
  26. const body = parseResponseJson(res)
  27. if (body.code === 200) {
  28. list.value = (body.data && body.data.list) || []
  29. }
  30. } finally {
  31. loading.value = false
  32. }
  33. }
  34. onMounted(() => {
  35. userStore.checkLoginStatus()
  36. if (!userStore.isLoggedIn) {
  37. uni.reLaunch({ url: '/pages/login/login' })
  38. return
  39. }
  40. if (!userStore.isClient) {
  41. uni.showToast({ title: '仅客户可访问', icon: 'none' })
  42. setTimeout(() => userStore.navigateToHome(), 1200)
  43. return
  44. }
  45. load()
  46. })
  47. onShow(() => {
  48. userStore.checkLoginStatus()
  49. if (!userStore.isLoggedIn || !userStore.isClient) return
  50. void load()
  51. })
  52. </script>
  53. <template>
  54. <view class="page client-theme client-subpage">
  55. <view class="client-subpage-hero refund-hero">
  56. <text class="client-subpage-hero__title">退款记录</text>
  57. <text class="client-subpage-hero__sub">查看退款进度与金额</text>
  58. </view>
  59. <scroll-view scroll-y class="client-subpage-scroll refund-scroll" :show-scrollbar="true">
  60. <view class="client-subpage-body refund-body">
  61. <view v-if="loading" class="hint">加载中...</view>
  62. <view v-else-if="list.length === 0" class="hint">暂无退款记录</view>
  63. <view
  64. v-for="row in list"
  65. :key="row.id"
  66. class="card"
  67. hover-class="card--pressed"
  68. :hover-stay-time="100"
  69. >
  70. <view class="line">
  71. <text class="no">{{ row.refundNo || row.id }}</text>
  72. <text class="st">{{ statusText[row.status] || row.status }}</text>
  73. </view>
  74. <view class="sub-row">
  75. <text class="sub">订单 {{ row.orderNo || '—' }}</text>
  76. <SqCopyBtn v-if="row.orderNo" class="copy" :text="row.orderNo" label="订单号" icon-only />
  77. </view>
  78. <text class="amt">¥{{ formatYuan(row.refundAmount) }}</text>
  79. <text class="time">{{ row.refundTime || row.createAt }}</text>
  80. </view>
  81. </view>
  82. </scroll-view>
  83. </view>
  84. </template>
  85. <style lang="scss" scoped>
  86. .page {
  87. min-height: 100vh;
  88. background: var(--c-bg);
  89. box-sizing: border-box;
  90. }
  91. .refund-scroll {
  92. flex: 1;
  93. min-height: 0;
  94. height: 0;
  95. }
  96. .card--pressed {
  97. opacity: 0.94;
  98. }
  99. .hint {
  100. text-align: center;
  101. color: var(--c-muted);
  102. padding: 80rpx 0;
  103. font-size: 28rpx;
  104. }
  105. .card {
  106. background: var(--c-card);
  107. border: 1rpx solid var(--c-border);
  108. border-radius: var(--c-radius-card);
  109. padding: 24rpx;
  110. margin-bottom: 16rpx;
  111. }
  112. .line {
  113. display: flex;
  114. justify-content: space-between;
  115. align-items: center;
  116. }
  117. .no {
  118. font-size: 28rpx;
  119. color: var(--c-text);
  120. font-weight: 600;
  121. }
  122. .st {
  123. font-size: 24rpx;
  124. color: var(--c-muted);
  125. }
  126. .sub {
  127. display: block;
  128. font-size: 26rpx;
  129. color: var(--c-muted);
  130. margin-top: 12rpx;
  131. }
  132. .sub-row {
  133. display: flex;
  134. align-items: center;
  135. justify-content: space-between;
  136. gap: 12rpx;
  137. margin-top: 12rpx;
  138. }
  139. .sub-row .sub {
  140. flex: 1;
  141. min-width: 0;
  142. margin-top: 0;
  143. overflow: hidden;
  144. text-overflow: ellipsis;
  145. white-space: nowrap;
  146. }
  147. .copy {
  148. flex: 0 0 auto;
  149. }
  150. .amt {
  151. display: block;
  152. font-size: 32rpx;
  153. color: var(--c-danger);
  154. font-weight: bold;
  155. margin-top: 12rpx;
  156. }
  157. .time {
  158. display: block;
  159. font-size: 22rpx;
  160. color: #c0c4cc;
  161. margin-top: 12rpx;
  162. }
  163. </style>