巴青农资商城

aftersale-detail.vue 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. <template>
  2. <view class="aftersale-detail-page">
  3. <view v-if="pageLoading" class="aftersale-detail-state">
  4. <u-loading-icon mode="circle" />
  5. </view>
  6. <view v-else-if="pageError" class="aftersale-detail-state">
  7. <u-empty mode="page" :text="pageError" icon-size="80" />
  8. <u-button type="primary" text="重试" size="small" custom-style="margin-top:24rpx" @click="loadDetail" />
  9. </view>
  10. <scroll-view v-else-if="detail" class="aftersale-detail-scroll" scroll-y>
  11. <view class="as-progress">
  12. <text class="as-progress__title">{{ detail.statusText }}</text>
  13. <text class="as-progress__step">{{ progressText }}</text>
  14. </view>
  15. <view class="as-card">
  16. <text class="as-card__title">商品信息</text>
  17. <view class="as-goods">
  18. <image-preview class="as-goods__pic" :src="detail.goodsImage" />
  19. <view class="as-goods__info">
  20. <text class="as-goods__name">{{ detail.goodsName }}</text>
  21. <text
  22. v-for="(spec, idx) in detail.specList"
  23. :key="idx"
  24. class="as-goods__spec"
  25. >{{ spec }}</text>
  26. </view>
  27. </view>
  28. </view>
  29. <view class="as-card">
  30. <text class="as-card__title">售后信息</text>
  31. <view class="as-row">
  32. <text class="as-row__label">售后编号</text>
  33. <text class="as-row__val">{{ detail.aftersaleNo }}</text>
  34. </view>
  35. <view class="as-row">
  36. <text class="as-row__label">订单编号</text>
  37. <text class="as-row__val">{{ detail.orderNo || '—' }}</text>
  38. </view>
  39. <view class="as-row">
  40. <text class="as-row__label">申请类型</text>
  41. <text class="as-row__val">{{ detail.applyTypeText }}</text>
  42. </view>
  43. <view class="as-row">
  44. <text class="as-row__label">售后原因</text>
  45. <text class="as-row__val">{{ detail.applyReason }}</text>
  46. </view>
  47. <view v-if="detail.returnQuantity" class="as-row">
  48. <text class="as-row__label">退货数量</text>
  49. <text class="as-row__val">{{ detail.returnQuantity }}</text>
  50. </view>
  51. <view class="as-row">
  52. <text class="as-row__label">申请金额</text>
  53. <text class="as-row__val">¥{{ detail.applyAmountText }}</text>
  54. </view>
  55. <view class="as-row">
  56. <text class="as-row__label">申请时间</text>
  57. <text class="as-row__val">{{ detail.createTime }}</text>
  58. </view>
  59. <view v-if="detail.finishTime" class="as-row">
  60. <text class="as-row__label">完结时间</text>
  61. <text class="as-row__val">{{ detail.finishTime }}</text>
  62. </view>
  63. <view v-if="detail.description" class="as-row">
  64. <text class="as-row__label">补充描述</text>
  65. <text class="as-row__val">{{ detail.description }}</text>
  66. </view>
  67. </view>
  68. <view v-if="detail.evidencePics && detail.evidencePics.length" class="as-card">
  69. <text class="as-card__title">凭证图片</text>
  70. <view class="as-pics">
  71. <image-preview
  72. v-for="(pic, idx) in detail.evidencePics"
  73. :key="idx"
  74. class="as-pics__item"
  75. :src="pic"
  76. preview
  77. :preview-list="detail.evidencePics"
  78. :preview-index="idx"
  79. />
  80. </view>
  81. </view>
  82. <view v-if="detail.processResult" class="as-card">
  83. <text class="as-card__title">处理结果</text>
  84. <text class="as-result">{{ detail.processResult }}</text>
  85. </view>
  86. </scroll-view>
  87. </view>
  88. </template>
  89. <script setup>
  90. import { ref, computed } from 'vue'
  91. import { onLoad, onShow } from '@dcloudio/uni-app'
  92. import { getAftersaleDetail } from '@/api/orderAftersale'
  93. import { mapAftersaleDetail } from '@/utils/orderDisplay'
  94. import { ensureApiToken } from '@/utils/apiAuth'
  95. const aftersaleId = ref('')
  96. const detail = ref(null)
  97. const pageLoading = ref(true)
  98. const pageError = ref('')
  99. const progressText = computed(() => {
  100. if (!detail.value) return ''
  101. if (detail.value.progressText) return detail.value.progressText
  102. const p = detail.value.progress
  103. if (p === 'FINISHED') return '商家处理 → 售后完结(当前:售后完结)'
  104. return '商家处理 → 售后完结(当前:商家处理)'
  105. })
  106. async function loadDetail() {
  107. if (!aftersaleId.value) return
  108. pageLoading.value = !detail.value
  109. pageError.value = ''
  110. try {
  111. const res = await getAftersaleDetail(aftersaleId.value)
  112. detail.value = mapAftersaleDetail(res.data)
  113. if (!detail.value) throw new Error('售后数据异常')
  114. } catch (e) {
  115. pageError.value = (e && e.message) || '加载失败'
  116. } finally {
  117. pageLoading.value = false
  118. }
  119. }
  120. onLoad((options) => {
  121. aftersaleId.value = options.aftersaleId || ''
  122. if (!aftersaleId.value) {
  123. pageError.value = '售后信息缺失'
  124. pageLoading.value = false
  125. }
  126. })
  127. onShow(() => {
  128. if (!ensureApiToken(false)) return
  129. if (!aftersaleId.value) return
  130. loadDetail()
  131. })
  132. </script>
  133. <style lang="scss" scoped>
  134. .aftersale-detail-page {
  135. min-height: 100vh;
  136. background: #f5f6f8;
  137. }
  138. .aftersale-detail-state {
  139. padding: 120rpx 48rpx;
  140. display: flex;
  141. flex-direction: column;
  142. align-items: center;
  143. }
  144. .aftersale-detail-scroll {
  145. height: 100vh;
  146. padding: 16rpx 24rpx;
  147. box-sizing: border-box;
  148. }
  149. .as-progress {
  150. padding: 32rpx 24rpx;
  151. margin-bottom: 16rpx;
  152. background: linear-gradient(135deg, #43a047 0%, #2e7d32 100%);
  153. border-radius: 12rpx;
  154. color: #fff;
  155. }
  156. .as-progress__title {
  157. display: block;
  158. font-size: 34rpx;
  159. font-weight: 600;
  160. }
  161. .as-progress__step {
  162. display: block;
  163. margin-top: 12rpx;
  164. font-size: 26rpx;
  165. opacity: 0.9;
  166. }
  167. .as-card {
  168. margin-bottom: 16rpx;
  169. padding: 24rpx;
  170. background: #fff;
  171. border-radius: 12rpx;
  172. }
  173. .as-card__title {
  174. display: block;
  175. margin-bottom: 16rpx;
  176. font-size: 28rpx;
  177. font-weight: 600;
  178. color: #333;
  179. }
  180. .as-goods {
  181. display: flex;
  182. }
  183. .as-goods__pic {
  184. width: 140rpx;
  185. height: 140rpx;
  186. border-radius: 8rpx;
  187. background: #eee;
  188. }
  189. .as-goods__info {
  190. flex: 1;
  191. margin-left: 16rpx;
  192. }
  193. .as-goods__name {
  194. display: block;
  195. font-size: 28rpx;
  196. color: #333;
  197. }
  198. .as-goods__spec {
  199. display: block;
  200. margin-top: 6rpx;
  201. font-size: 24rpx;
  202. color: #999;
  203. }
  204. .as-row {
  205. display: flex;
  206. padding: 10rpx 0;
  207. font-size: 26rpx;
  208. }
  209. .as-row__label {
  210. width: 160rpx;
  211. color: #999;
  212. flex-shrink: 0;
  213. }
  214. .as-row__val {
  215. flex: 1;
  216. color: #333;
  217. word-break: break-all;
  218. }
  219. .as-pics {
  220. display: flex;
  221. flex-wrap: wrap;
  222. gap: 12rpx;
  223. }
  224. .as-pics__item {
  225. width: 160rpx;
  226. height: 160rpx;
  227. border-radius: 8rpx;
  228. background: #eee;
  229. }
  230. .as-result {
  231. font-size: 28rpx;
  232. color: #333;
  233. line-height: 1.6;
  234. }
  235. </style>