order-modal.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. <script setup lang="tsx">
  2. import { computed, ref } from 'vue';
  3. import { fetchGetAfterSalesOrderDetail } from '@/service/api/delivery/after-sales-order';
  4. import { useAppStore } from '@/store/modules/app';
  5. import { copyTextToClipboard } from '@/utils/zt';
  6. import { useModal } from '@/components/zt/Modal/hooks/useModal';
  7. import { TypeText, orderColumns, refundEnum, refundStatus, refundTime, refundTimeEnum } from './after-sales-order';
  8. const [registerModal, { openModal, setModalLoading }] = useModal({
  9. title: '处理退款',
  10. width: 1200,
  11. height: 800,
  12. isShowHeaderText: false,
  13. showFooter: false
  14. });
  15. const appStore = useAppStore();
  16. const orderInfo = ref<Api.delivery.OrderRefund>();
  17. const isRefundIng = ref(false);
  18. const goodsMoney = computed(() => {
  19. // 后端不算,让前端算
  20. return orderInfo.value?.orderRefundSkuList?.reduce((acc, item) => {
  21. return acc + Number(item.orderItem.productTotalAmount) * Number(item.orderItem.prodCount);
  22. }, 0);
  23. });
  24. defineExpose({
  25. handleOpenOrder
  26. });
  27. async function handleOpenOrder(refundId: number) {
  28. openModal();
  29. setModalLoading(true);
  30. const { data, error } = await fetchGetAfterSalesOrderDetail(refundId);
  31. if (!error) {
  32. orderInfo.value = data;
  33. }
  34. setModalLoading(false);
  35. }
  36. function getImgFils() {
  37. return orderInfo.value?.photoFiles?.split(',').map(item => {
  38. return `${import.meta.env.VITE_OSS_BASE_URL}${item}`;
  39. });
  40. }
  41. </script>
  42. <template>
  43. <BasicModal @register="registerModal" @after-leave="isRefundIng = false">
  44. <div v-if="orderInfo">
  45. <NFlex justify="space-between">
  46. <NFlex vertical>
  47. <NTag>
  48. <div class="flex items-center">
  49. 退款编号: {{ orderInfo?.refundSn }}
  50. <div @click="copyTextToClipboard(orderInfo.refundSn)">
  51. <SvgIcon icon="bxs:copy" class="mx-3 cursor-pointer text-[#f97316]"></SvgIcon>
  52. </div>
  53. </div>
  54. </NTag>
  55. <NTag>申请人: {{ orderInfo.receiver || '---' }} | 申请时间:{{ orderInfo.applyTime }}</NTag>
  56. </NFlex>
  57. <NFlex vertical>
  58. <div class="text-16px font-semibold">
  59. {{ refundStatus[orderInfo.returnMoneySts as keyof typeof refundStatus] }}
  60. </div>
  61. <div class="text-gray">
  62. <template v-if="orderInfo.returnMoneySts == refundEnum.BUYER_APPLY">
  63. <div class="text-12px">逾期未处理,将自动退款给买家。</div>
  64. <div class="mt3 text-15px">
  65. <div>温馨提示</div>
  66. <div>如果你同意,将直接退款给买家。</div>
  67. <div>如果你拒绝,最好和买家先协商一致。</div>
  68. <div>如果你逾期未处理,视作同意买家申请,系统将自动退款给买家。</div>
  69. </div>
  70. </template>
  71. <template v-if="orderInfo.returnMoneySts == refundEnum.REVOKE_APPLY">
  72. <div>用户主动撤回申请,退款关闭。</div>
  73. </template>
  74. <template v-if="orderInfo.returnMoneySts == refundEnum.SELLER_REFUSE">
  75. <div>卖家拒绝了用户的申请</div>
  76. </template>
  77. <template v-if="orderInfo.returnMoneySts == refundEnum.REFUND_SUCCESS">
  78. <div>已完成退款,具体到账时间请用户查询支付账户</div>
  79. </template>
  80. </div>
  81. </NFlex>
  82. </NFlex>
  83. <NDivider />
  84. <NDescriptions bordered :column="appStore.isMobile ? 1 : 4">
  85. <NDescriptionsItem label="售后信息">
  86. <div>售后方式:{{ TypeText[orderInfo.applyType - 1] || '未知状况' }}</div>
  87. <div>退款原因:{{ orderInfo.buyerReason || '---' }}</div>
  88. <div>退款件数: {{ orderInfo.goodsNum || '---' }}件</div>
  89. </NDescriptionsItem>
  90. <NDescriptionsItem label="购买信息">
  91. <div>商品总额: {{ goodsMoney || '---' }}</div>
  92. <div>配送费(快递): {{ orderInfo.freightAmount || '---' }}元</div>
  93. <div>积分抵扣: {{ (orderInfo.orderOffsetPoints / 100).toFixed(2) || '---' }}元</div>
  94. <div>实际付款: {{ orderInfo.orderActualTotal || '---' }}元</div>
  95. </NDescriptionsItem>
  96. </NDescriptions>
  97. <NDivider />
  98. <NCard title="退款商品" :bordered="false">
  99. <NDataTable :columns="orderColumns" :data="orderInfo.orderRefundSkuList" :bordered="false" />
  100. </NCard>
  101. <div class="flex items-center justify-end">
  102. <div class="flex flex-wrap items-center">
  103. <div class="text-16px font-semibold">退款总金额: {{ orderInfo.refundTotalMoney || '--' }}元</div>
  104. <div v-if="orderInfo.returnMoneySts == refundEnum.REFUND_SUCCESS" class="ml2 flex items-center text-gray">
  105. <div>退还金额:{{ orderInfo.refundAmount }}</div>
  106. <div class="ml2">退还积分:{{ orderInfo.offsetPoints }} (已过期{{ orderInfo.refundExpiredScore }})</div>
  107. </div>
  108. </div>
  109. </div>
  110. <div v-if="orderInfo.orderRefundRecordList" class="mt3">
  111. <!-- 1-申请原因,2-商家待审核,5-用户待发货,7-待商家收货,10-审核通过,20-驳回,30-退款成功 -->
  112. <NTimeline>
  113. <NTimelineItem
  114. v-for="item in orderInfo.orderRefundRecordList"
  115. :key="item.id"
  116. :type="item.auditStatus == refundTimeEnum.RefundSuccess ? 'success' : 'default'"
  117. :title="refundTime[item.auditStatus as keyof typeof refundTime]"
  118. :time="item.createTime"
  119. >
  120. <div>{{ item.instructions }}</div>
  121. <div
  122. v-if="item.auditStatus == refundTimeEnum.Reason && orderInfo.photoFiles"
  123. class="mt2 flex flex-wrap items-center"
  124. >
  125. <template v-for="items in getImgFils()" :key="items">
  126. <NImage :width="100" :height="100" :src="items" lazy class="mb2 mr3 h100px w100px" object-fit="cover" />
  127. </template>
  128. </div>
  129. </NTimelineItem>
  130. </NTimeline>
  131. </div>
  132. </div>
  133. </BasicModal>
  134. </template>
  135. <style scoped></style>