orderDetail.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. <route lang="json5" type="page">
  2. {
  3. layout: 'default',
  4. style: {
  5. navigationBarTitleText: 'My Orders',
  6. navigationBarBackgroundColor: '#fff',
  7. },
  8. }
  9. </route>
  10. <script lang="ts" setup>
  11. import { getConfigByCode } from '@/api/common'
  12. import { bindingAddress, orderCancel, orderDetail, orderPink, orderStatusEnum } from '@/api/order'
  13. import DialogBox from '@/components/DialogBox/DialogBox.vue'
  14. import { DialogUtils } from '@/components/DialogBox/utils'
  15. import { t } from '@/locale'
  16. import { formatNumber } from '@/utils'
  17. import { getPageParams, toPage } from '@/utils/page'
  18. import { toast } from '@/utils/toast'
  19. defineOptions({
  20. name: 'OrderDetail', // 订单详情
  21. })
  22. // z-paging
  23. const paging = ref(null)
  24. const id = ref<any>()
  25. const detail = ref<any>({})
  26. const orderStatusEnumData = ref<any>([])
  27. const openRedEnvelopeRate = ref<any>()
  28. const joinRedEnvelopeRate = ref<any>()
  29. // DialogBox 函数式调用配置
  30. const dialogConfig = ref<any>({})
  31. async function getConfig(code: string) {
  32. try {
  33. const res = await getConfigByCode({ code })
  34. if (res.code === '200') {
  35. switch (code) {
  36. case 'open_red_envelope_rate':
  37. openRedEnvelopeRate.value = res.data.valueInfo
  38. break
  39. case 'join_red_envelope_rate':
  40. joinRedEnvelopeRate.value = res.data.valueInfo
  41. break
  42. default:
  43. break
  44. }
  45. }
  46. }
  47. catch {
  48. }
  49. }
  50. async function getOrderStatus() {
  51. try {
  52. const res = await orderStatusEnum({ id: 1 })
  53. if (res.code === '200') {
  54. orderStatusEnumData.value = res.data
  55. }
  56. }
  57. catch {
  58. }
  59. }
  60. async function getDetail() {
  61. getPink()
  62. try {
  63. const res = await orderDetail({ id: id.value })
  64. if (res.code === '200') {
  65. detail.value = res.data
  66. paging.value.complete()
  67. }
  68. }
  69. catch {}
  70. }
  71. const pinkList = ref<any>([])
  72. async function getPink() {
  73. try {
  74. const res = await orderPink({ id: id.value })
  75. if (res.code === '200') {
  76. pinkList.value = res.data
  77. }
  78. }
  79. catch {
  80. }
  81. }
  82. onLoad(async (options) => {
  83. getConfig('open_red_envelope_rate')
  84. getConfig('join_red_envelope_rate')
  85. const params = getPageParams(options)
  86. id.value = params.id
  87. await getOrderStatus()
  88. })
  89. onShow(() => {
  90. getDetail()
  91. })
  92. // 跳转到地址簿选择地址
  93. function selectAddress() {
  94. toPage('/pages/mine/addressBook', {
  95. selectMode: true,
  96. orderId: id.value,
  97. })
  98. }
  99. // 绑定地址到订单
  100. async function bindAddressToOrder(addressId: number) {
  101. try {
  102. uni.showLoading({
  103. title: t('addressBook.select.binding'),
  104. })
  105. const res = await bindingAddress({
  106. orderId: id.value,
  107. addressId,
  108. })
  109. if (res.code === '200') {
  110. toast.success(t('addressBook.select.success'))
  111. // 刷新订单详情
  112. getDetail()
  113. }
  114. else {
  115. toast.error(res.message || t('addressBook.select.failed'))
  116. }
  117. }
  118. catch (error: any) {
  119. console.error('Bind address error:', error)
  120. toast.error(t('addressBook.select.networkError'))
  121. }
  122. finally {
  123. uni.hideLoading()
  124. }
  125. }
  126. // 显示取消订单确认对话框
  127. function showCancelOrderDialog() {
  128. Object.assign(dialogConfig.value, DialogUtils.info(
  129. 'Are you sure you want to cancel this order?',
  130. {
  131. showCancel: true,
  132. confirmText: 'Yes, Cancel',
  133. cancelText: 'Keep Order',
  134. },
  135. ))
  136. }
  137. // 取消订单
  138. async function cancelOrder() {
  139. try {
  140. uni.showLoading({
  141. title: 'Cancelling order...',
  142. })
  143. const res = await orderCancel({ id: id.value })
  144. if (res.code === '200') {
  145. // 显示成功提示
  146. toast.success('Order cancelled successfully!')
  147. // 刷新订单详情
  148. getDetail()
  149. }
  150. else {
  151. // 显示错误提示
  152. toast.error(res.message || 'Failed to cancel order. Please try again.')
  153. }
  154. }
  155. catch (error: any) {
  156. console.error('Cancel order error:', error)
  157. // 显示错误提示
  158. toast.error('Network error. Please check your connection and try again.')
  159. }
  160. finally {
  161. uni.hideLoading()
  162. }
  163. }
  164. // 处理对话框确认事件
  165. function handleDialogConfirm() {
  166. const config = dialogConfig.value as any
  167. const { confirmText } = config
  168. if (confirmText === 'Yes, Cancel') {
  169. // 确认取消订单
  170. cancelOrder()
  171. }
  172. // 关闭对话框
  173. handleDialogCancel()
  174. }
  175. // 处理对话框取消事件
  176. function handleDialogCancel() {
  177. // 关闭对话框
  178. dialogConfig.value.show = false
  179. }
  180. // 处理对话框关闭事件
  181. function handleDialogClose() {
  182. dialogConfig.value.show = false
  183. }
  184. </script>
  185. <template>
  186. <z-paging ref="paging" refresher-only @refresh="getDetail">
  187. <view class="pt-20rpx">
  188. <!-- 状态显示 -->
  189. <template v-if="detail.status !== 4">
  190. <!-- 已中奖 -->
  191. <view v-if="detail?.storePink?.status === 2 && detail?.storePink?.lId === 1" class="mb-20rpx bg-#17AA68/80 py-20rpx text-center text-28rpx text-white">
  192. Congrats,You won the prize in this group!已中奖
  193. <br>
  194. You have received
  195. <text class="text-[var(--wot-color-theme)]">
  196. ৳{{ 10 }}
  197. </text>
  198. group opening reward
  199. </view>
  200. <!-- 未中奖 -->
  201. <view v-else-if="detail?.storePink?.status === 2 && detail?.storePink?.lId === 0" class="mb-20rpx bg-#E61B28/80 py-20rpx text-center text-28rpx text-white">
  202. So sorry, You didn't win in this group
  203. <br>
  204. You have received
  205. <text class="text-#66C59B">
  206. ৳8
  207. </text>
  208. group opening reward
  209. </view>
  210. <!-- 未开奖||未支付 -->
  211. <view v-else-if="detail?.storePink?.status === 1 || detail?.status === 1" class="mb-20rpx bg-#fff py-20rpx text-center text-28rpx text-white">
  212. <text v-if="detail?.storePink?.status === 1" class="text-[var(--wot-color-theme)]">
  213. Please wait for the draw of this group
  214. </text>
  215. <text v-else class="text-[var(--wot-color-theme)]">
  216. Please make payment within:29:59
  217. </text>
  218. </view>
  219. <!-- 拼团头像 -->
  220. <view class="mb-20rpx bg-white px-20rpx py-20rpx text-center">
  221. <image v-for="i in 10" :key="i" class="mx-4rpx mb-8rpx h-80rpx w-80rpx rounded-full" src="/static/images/avatar.jpg" />
  222. </view>
  223. </template>
  224. <!-- 地址 -->
  225. <view v-if="detail?.storePink?.status === 2 && detail?.storePink?.lId === 1" class="mb-20rpx bg-white px-24rpx py-20rpx">
  226. <!-- 无地址 -->
  227. <template v-if="!detail.orderAddressVO">
  228. <view class="flex items-center justify-between" @click="selectAddress">
  229. <view class="text-28rpx text-[var(--wot-color-theme)]">
  230. Please provide your shipping address
  231. </view>
  232. <wd-icon name="arrow-right" color="#7D7D7D" size="28rpx" />
  233. </view>
  234. </template>
  235. <!-- 有地址 -->
  236. <template v-else>
  237. <view class="mb-18rpx flex justify-between border-b-1 border-b-#E1E1E1 border-b-solid pb-18rpx text-24rpx">
  238. <!-- 物流信息 -->
  239. <view>{{ detail.deliveryName }}</view>
  240. <view> DHL:{{ detail.deliveryCode || '-' }}</view>
  241. </view>
  242. <view class="mb-20rpx text-24rpx">
  243. <text class="mr-20rpx">
  244. {{ detail?.orderAddressVO?.realName }}
  245. </text>
  246. <text>{{ detail?.orderAddressVO?.phone }}</text>
  247. </view>
  248. <view class="text-22rpx text-#3A444C">
  249. {{ detail?.orderAddressVO?.province }} {{ detail?.orderAddressVO?.city }} {{ detail?.orderAddressVO?.district }} {{ detail?.orderAddressVO?.detail }} {{ detail?.orderAddressVO?.postCode }}
  250. </view>
  251. </template>
  252. </view>
  253. <!-- 商品信息 -->
  254. <wd-card type="rectangle" custom-class="px-24rpx! py-6rpx!" custom-content-class="py-18rpx!" custom-title-class="py-18rpx!" @click="toPage('/pages/productDetail/productDetail', { productId: detail?.orderInfoVO?.[0].productId })">
  255. <template #title>
  256. <view class="flex items-center justify-between">
  257. <view class="text-28rpx text-#000">
  258. Order ID:{{ detail?.orderInfoVO?.[0].orderNo }}
  259. </view>
  260. <wd-text size="26rpx" type="primary" :text="orderStatusEnumData.find((i:any) => i.code === detail?.status)?.name" />
  261. </view>
  262. </template>
  263. <view class="flex items-center gap-24rpx">
  264. <view class="h-140rpx w-140rpx shrink-0">
  265. <image
  266. :src="detail?.orderInfoVO?.[0]?.image"
  267. class="h-full w-full"
  268. mode="aspectFit"
  269. />
  270. </view>
  271. <view class="flex-1">
  272. <view class="line-clamp-2 text-28rpx text-#000">
  273. {{ detail?.orderInfoVO?.[0].productName }}
  274. </view>
  275. <view class="py-4rpx text-24rpx text-#3A444C">
  276. Color:{{ detail?.orderInfoVO?.[0].sku }}
  277. </view>
  278. <view class="flex items-center justify-between text-24rpx">
  279. <view class="text-[var(--wot-color-theme)]">
  280. ৳ {{ formatNumber(detail?.orderInfoVO?.[0].price) }}
  281. </view>
  282. <view class="text-#3A444C">
  283. Quantity:{{ detail?.orderInfoVO?.[0].payNum }}
  284. </view>
  285. </view>
  286. </view>
  287. </view>
  288. </wd-card>
  289. <!-- 订单信息 -->
  290. <view class="bg-white px-24rpx">
  291. <view class="border-b-1 border-b-#E1E1E1 border-b-solid py-24rpx">
  292. <view class="mb-12rpx text-28rpx">
  293. Oder Summary
  294. </view>
  295. <view class="flex flex-col gap-16rpx text-#3A444C">
  296. <view class="flex items-center justify-between text-24rpx">
  297. <text>SubTotal</text>
  298. <text>৳{{ formatNumber(detail.totalPrice) }}</text>
  299. </view>
  300. </view>
  301. </view>
  302. <view class="border-b-1 border-b-#E1E1E1 border-b-solid py-24rpx">
  303. <view class="mb-12rpx text-28rpx">
  304. Paid by
  305. </view>
  306. <view class="flex flex-col gap-16rpx text-#3A444C">
  307. <view class="flex items-center justify-between text-24rpx">
  308. <text>SubTotal</text>
  309. <text>৳{{ formatNumber(detail.payPrice) }}</text>
  310. </view>
  311. </view>
  312. </view>
  313. <view class="py-24rpx">
  314. <view class="flex flex-col gap-16rpx text-#3A444C">
  315. <view class="flex items-center justify-between text-24rpx">
  316. <text>Placed on</text>
  317. <text>{{ detail.createTime }}</text>
  318. </view>
  319. </view>
  320. </view>
  321. </view>
  322. </view>
  323. <template #bottom>
  324. <view class="flex items-center justify-end bg-white/60 px-28rpx py-30rpx backdrop-blur-20">
  325. <!-- 取消订单按钮 -->
  326. <wd-button
  327. v-if="detail?.status === 1"
  328. custom-class="mr-16rpx!"
  329. plain
  330. @click="showCancelOrderDialog"
  331. >
  332. Cancel
  333. </wd-button>
  334. <wd-button>Share Now</wd-button>
  335. </view>
  336. </template>
  337. <!-- DialogBox 函数式调用 -->
  338. <DialogBox
  339. v-bind="dialogConfig"
  340. @confirm="handleDialogConfirm"
  341. @cancel="handleDialogCancel"
  342. @close="handleDialogClose"
  343. />
  344. </z-paging>
  345. </template>
  346. <style lang="scss" scoped>
  347. //
  348. </style>