normal-modal.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <script setup lang="ts">
  2. import { computed, ref, useTemplateRef } from 'vue';
  3. import dayjs from 'dayjs';
  4. import { fetchGetNomalOrderInfo } from '@/service/api/delivery/normal-orde';
  5. import { useAppStore } from '@/store/modules/app';
  6. import { copyTextToClipboard } from '@/utils/zt';
  7. import { useModal } from '@/components/zt/Modal/hooks/useModal';
  8. import { ShippingButton, dvyStatus, orderColumns, orderStatusEnum } from '../normal-order';
  9. import DeliveryModal from './delivery-modal.vue';
  10. const [registerModal, { openModal, setModalLoading }] = useModal({
  11. title: '订单详情',
  12. isShowHeaderText: false,
  13. showFooter: false,
  14. width: 1200,
  15. height: 800
  16. });
  17. const orderInfo = ref<Api.delivery.deliveryOrder>();
  18. const appStore = useAppStore();
  19. const TimeDown = ref<number>(0);
  20. const ShipmentRef = useTemplateRef('Shipment');
  21. const emit = defineEmits<{
  22. (e: 'finish'): void;
  23. }>();
  24. async function open(orderNumber: string) {
  25. openModal();
  26. setModalLoading(true);
  27. const { data, error } = await fetchGetNomalOrderInfo(orderNumber);
  28. if (!error) {
  29. orderInfo.value = data;
  30. if (orderInfo.value.hbLogisticStatus == orderStatusEnum.WAIT_PAY) {
  31. const createTime = dayjs(orderInfo.value.createTime);
  32. const currentTime = dayjs();
  33. const elapsed = currentTime.diff(createTime);
  34. const fifteenMinutesInMillis = 15 * 60 * 1000;
  35. TimeDown.value = fifteenMinutesInMillis - elapsed;
  36. }
  37. }
  38. setModalLoading(false);
  39. }
  40. defineExpose({ open });
  41. function handleFinish() {
  42. open(String(orderInfo.value?.orderNumber));
  43. emit('finish');
  44. }
  45. const isRefund = computed(() => {
  46. const goodsData = orderInfo.value?.orderItems?.find(it => it.refundIngCount == 1);
  47. return Boolean(goodsData);
  48. });
  49. function handleShipment() {
  50. if (isRefund.value) {
  51. window.$message?.error('当前订单正在申请退款中');
  52. return;
  53. }
  54. ShipmentRef.value?.handleOpenOrder(String(orderInfo.value?.orderNumber));
  55. }
  56. const currentSteps = computed(() => {
  57. switch (orderInfo.value?.hbOrderStatus) {
  58. case orderStatusEnum.WAIT_PAY:
  59. return 1;
  60. case orderStatusEnum.ORDER_ACCEPT:
  61. return 2;
  62. case orderStatusEnum.ORDER_WAIT_DELIVERY:
  63. return 2;
  64. case orderStatusEnum.WAIT_DELIVERY:
  65. return 2;
  66. case orderStatusEnum.ORDER_DELIVERY:
  67. return 3;
  68. case orderStatusEnum.ORDER_ARRIVE:
  69. return 3;
  70. case orderStatusEnum.ORDER_COMPLETE:
  71. return 4;
  72. default:
  73. return 1;
  74. }
  75. });
  76. function handleCopy() {
  77. copyTextToClipboard(String(orderInfo.value?.orderNumber));
  78. }
  79. </script>
  80. <template>
  81. <div>
  82. <BasicModal @register="registerModal" @after-leave="orderInfo = undefined">
  83. <div v-if="orderInfo">
  84. <NFlex justify="space-between" align="center">
  85. <NFlex>
  86. <NTag>
  87. <div class="flex items-center">
  88. 订单编号: {{ orderInfo?.orderNumber }}
  89. <div @click="handleCopy">
  90. <SvgIcon icon="bxs:copy" class="mx-3 cursor-pointer text-[#f97316]"></SvgIcon>
  91. </div>
  92. </div>
  93. </NTag>
  94. <NTag>下单时间: {{ orderInfo?.createTime }}</NTag>
  95. </NFlex>
  96. <NFlex vertical>
  97. <template v-if="orderInfo.hbOrderStatus == orderStatusEnum.WAIT_PAY">
  98. <div class="text-16px font-semibold">商品已拍下,等待买家付款</div>
  99. <div class="text-gray">
  100. 如买家未在
  101. <NTag :type="TimeDown > 300094 ? 'success' : 'error'">
  102. <NCountdown :duration="TimeDown" @finish="handleFinish" />
  103. </NTag>
  104. 内付款,订单将 自动关闭。
  105. </div>
  106. </template>
  107. <template v-if="!orderInfo.dvyFlowId">
  108. <template v-if="ShippingButton.includes(orderInfo.hbOrderStatus)">
  109. <div class="text-16px font-semibold">等待商家发货</div>
  110. <NButton size="small" type="primary" @click="handleShipment">发货</NButton>
  111. </template>
  112. </template>
  113. <template v-if="orderInfo.hbOrderStatus == orderStatusEnum.ORDER_ARRIVE">
  114. <div class="text-16px font-semibold">等待买家收货</div>
  115. <div>商家已发货,等待确认收货</div>
  116. </template>
  117. <template v-if="orderInfo.hbOrderStatus == orderStatusEnum.ORDER_CANCEL">
  118. <div class="text-16px font-semibold">已取消</div>
  119. <div>取消原因:{{ orderInfo.cancelReason || '未知取消原因' }}</div>
  120. </template>
  121. <template v-if="orderInfo.hbOrderStatus == orderStatusEnum.ORDER_COMPLETE">
  122. <div class="text-16px font-semibold">交易成功</div>
  123. <div>买家已收货</div>
  124. </template>
  125. </NFlex>
  126. </NFlex>
  127. <NDivider />
  128. <template v-if="orderInfo.hbOrderStatus != orderStatusEnum.ORDER_CANCEL">
  129. <div class="p3">
  130. <NSteps :current="currentSteps" :vertical="appStore.isMobile">
  131. <NStep title="用户下单" :description="orderInfo.createTime" />
  132. <NStep title="买家已付款" :description="orderInfo.payTime" />
  133. <NStep title="卖家已发货" :description="orderInfo.dvyTime" />
  134. <NStep title="买家已收货" :description="orderInfo.finallyTime" />
  135. </NSteps>
  136. </div>
  137. <NDivider />
  138. </template>
  139. <NDescriptions bordered :column="appStore.isMobile ? 1 : 4">
  140. <NDescriptionsItem label="收货人信息">
  141. <div>收货人姓名:{{ orderInfo?.userAddrOrder?.receiver || '---' }}</div>
  142. <div>收货人手机号:{{ orderInfo?.userAddrOrder?.mobile || '---' }}</div>
  143. <div>收货地址:{{ orderInfo?.userAddrOrder?.address || '---' }}</div>
  144. </NDescriptionsItem>
  145. <NDescriptionsItem label="配送信息">
  146. <div>配送方式: {{ dvyStatus[orderInfo.dvyType as keyof typeof dvyStatus] || '暂无' }}</div>
  147. </NDescriptionsItem>
  148. <NDescriptionsItem label="付款信息">
  149. <div>实付金额:{{ orderInfo.actualTotal }}元</div>
  150. <div>
  151. 付款方式:{{
  152. orderInfo.hbOrderStatus == orderStatusEnum.WAIT_PAY ||
  153. orderInfo.hbOrderStatus == orderStatusEnum.ORDER_CANCEL
  154. ? '暂无'
  155. : '微信'
  156. }}
  157. </div>
  158. <div>付款时间:{{ orderInfo.payTime || '暂无' }}</div>
  159. </NDescriptionsItem>
  160. <NDescriptionsItem label="买家信息">
  161. <div>买家昵称:{{ orderInfo?.nickName || '---' }}</div>
  162. <div>买家电话:{{ orderInfo?.userMobile || '---' }}</div>
  163. <div>买家留言:{{ orderInfo?.remarks || '暂无' }}</div>
  164. </NDescriptionsItem>
  165. </NDescriptions>
  166. <NDivider />
  167. <NCard title="订单信息" :bordered="false">
  168. <NDataTable :columns="orderColumns" :data="orderInfo.orderItems" :bordered="false" />
  169. </NCard>
  170. <NCard title="费用信息" :bordered="false">
  171. <NTable :single-line="false">
  172. <NThead>
  173. <NTr>
  174. <NTh>费用类型</NTh>
  175. <NTh>金额/元</NTh>
  176. </NTr>
  177. </NThead>
  178. <NTbody>
  179. <NTr>
  180. <NTd>商品总额</NTd>
  181. <NTd>{{ orderInfo.total }}</NTd>
  182. </NTr>
  183. <NTr>
  184. <NTd>配送费(快递)</NTd>
  185. <NTd>{{ orderInfo.freightAmount }}</NTd>
  186. </NTr>
  187. <NTr>
  188. <NTd>积分</NTd>
  189. <NTd>-{{ (Number(orderInfo.offsetPoints) / 100).toFixed(2) || 0 }}</NTd>
  190. </NTr>
  191. <NTr>
  192. <NTd v-if="orderInfo.hbOrderStatus == orderStatusEnum.WAIT_PAY">需付款</NTd>
  193. <NTd
  194. v-if="
  195. orderInfo.hbOrderStatus != orderStatusEnum.WAIT_PAY &&
  196. orderInfo.hbOrderStatus != orderStatusEnum.ORDER_CANCEL
  197. "
  198. >
  199. 实际付款
  200. </NTd>
  201. <NTd v-if="orderInfo.hbOrderStatus == orderStatusEnum.ORDER_CANCEL">应付款</NTd>
  202. <NTd>{{ orderInfo.actualTotal }}</NTd>
  203. </NTr>
  204. </NTbody>
  205. </NTable>
  206. </NCard>
  207. </div>
  208. </BasicModal>
  209. <DeliveryModal ref="Shipment" @finish="emit('finish')"></DeliveryModal>
  210. </div>
  211. </template>
  212. <style scoped></style>