index.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <script setup lang="ts">
  2. import type { AppMemberCouponVO } from '@/api/globals'
  3. import router from '@/router'
  4. definePage({
  5. name: 'voucher',
  6. layout: 'tabbar',
  7. islogin: true,
  8. style: {
  9. navigationBarTitleText: '抵扣券',
  10. navigationStyle: 'custom',
  11. },
  12. })
  13. const StaticUrl = import.meta.env.VITE_STATIC_BASE_URL
  14. // Tab 列表
  15. const tabList = ref([
  16. { label: '可用', value: 2 },
  17. { label: '已使用', value: 1 },
  18. { label: '已过期', value: 5 },
  19. { label: '未生效', value: 7 },
  20. ])
  21. const currentTab = ref(2)
  22. // 状态映射
  23. const statusMap = new Map([
  24. [2, '可用'],
  25. [1, '已使用'],
  26. [5, '已过期'],
  27. [7, '未生效'],
  28. ])
  29. // 分页请求
  30. const { data, send, isLastPage, page } = usePagination(
  31. (pageNum, pageSize) => Apis.app.get_smqjh_system_app_api_membercoupon_page({
  32. params: { pageNum, pageSize, useStatus: currentTab.value },
  33. }),
  34. {
  35. initialPage: 1,
  36. initialPageSize: 10,
  37. immediate: false,
  38. data: res => res.data?.list,
  39. append: true,
  40. },
  41. )
  42. // 切换 Tab
  43. function handleTabChange(value: number) {
  44. currentTab.value = value
  45. data.value = []
  46. page.value = 1
  47. send()
  48. }
  49. function handleUse(_item: AppMemberCouponVO) {
  50. router.pushTab({ name: 'home' })
  51. useTabbar().setTabbarItemActive('home')
  52. }
  53. // 取消订单(占位)
  54. function handleCancelOrder(_item: AppMemberCouponVO) {
  55. useGlobalToast().show('功能开发中')
  56. }
  57. // 付款(占位)
  58. function handlePay(_item: AppMemberCouponVO) {
  59. useGlobalToast().show('功能开发中')
  60. }
  61. // 计算倒计时剩余毫秒数
  62. function getCountdownTime(orderCreateTime?: string): number {
  63. if (!orderCreateTime)
  64. return 0
  65. const createTime = new Date(orderCreateTime).getTime()
  66. const expireTime = createTime + 15 * 60 * 1000 // 假设15分钟支付有效期
  67. const remaining = expireTime - Date.now()
  68. return remaining > 0 ? remaining : 0
  69. }
  70. onShow(() => {
  71. data.value = []
  72. page.value = 1
  73. send()
  74. })
  75. onReachBottom(() => {
  76. if (!isLastPage.value) {
  77. page.value++
  78. }
  79. })
  80. watch(() => currentTab.value, () => {
  81. data.value = []
  82. page.value = 1
  83. send()
  84. })
  85. </script>
  86. <template>
  87. <view class="min-h-100vh bg-#f5f5f5">
  88. <!-- Tab 切换 -->
  89. <view class="sticky top-0 z-10 flex items-center justify-between bg-white px24rpx">
  90. <view
  91. v-for="item in tabList"
  92. :key="item.value"
  93. class="py24rpx text-28rpx"
  94. :class="[currentTab === item.value ? 'text-[var(--them-color)] font-semibold border-b-4rpx border-[var(--them-color)]' : 'text-#666']"
  95. @click="handleTabChange(item.value)"
  96. >
  97. {{ item.label }}
  98. </view>
  99. </view>
  100. <!-- 券列表 -->
  101. <view class="px24rpx pt20rpx">
  102. <view
  103. v-for="item in data"
  104. :key="item.id"
  105. class="mb20rpx rounded-16rpx bg-white px24rpx py28rpx"
  106. >
  107. <view @click="router.push({ name: 'voucherDetail', params: { id: item.id as string } })">
  108. <!-- 券信息头部 -->
  109. <view class="flex items-center justify-between">
  110. <view class="flex items-center">
  111. <image
  112. :src="`${StaticUrl}/smqjh-reful-juan.png`"
  113. class="mr12rpx h32rpx w32rpx"
  114. />
  115. <view class="text-30rpx font-semibold">
  116. 抵扣{{ item.discountMoney }}元(满{{ item.amountMoney }}元可用)
  117. </view>
  118. </view>
  119. <!-- 待支付倒计时 -->
  120. <view v-if="item.lockStatus === 1 && currentTab === 2" class="text-24rpx text-#1890ff">
  121. 待支付(<wd-count-down :time="getCountdownTime(item.orderCreateTime)" format="还剩mm:ss" />)
  122. </view>
  123. </view>
  124. <!-- 券详情 -->
  125. <view class="mt16rpx text-26rpx text-#999">
  126. 适用:全部合作油站
  127. </view>
  128. <view class="mt12rpx text-26rpx text-#999">
  129. 有效期至:{{ item.expirationTime }}
  130. </view>
  131. <view class="mt12rpx text-26rpx text-#999">
  132. 可抵扣:<text class="text-#ff4d3a">
  133. ¥{{ item.discountMoney }}
  134. </text>
  135. </view>
  136. <view class="mt12rpx text-26rpx text-#999">
  137. 状态:{{ statusMap.get(item.useStatus as number) || '' }}
  138. </view>
  139. </view>
  140. <!-- 操作按钮区域 -->
  141. <view v-if="currentTab === 2" class="mt20rpx">
  142. <!-- 未被锁定 - 显示去使用 -->
  143. <view v-if="item.lockStatus !== 1" class="flex justify-end">
  144. <wd-button size="small" plain custom-class="use-btn" @click="handleUse(item)">
  145. 去使用
  146. </wd-button>
  147. </view>
  148. <!-- 被锁定 - 显示订单信息和操作 -->
  149. <view v-else>
  150. <view class="flex items-center text-26rpx text-#1890ff">
  151. <wd-icon name="info-circle" size="28rpx" color="#1890ff" class="mr8rpx" />
  152. 当前订单未支付,券被占用
  153. </view>
  154. <view class="mt16rpx flex items-center justify-between">
  155. <view class="text-26rpx text-#999">
  156. 订单号:{{ item.lockOrderId }}
  157. </view>
  158. <view class="flex items-center gap-16rpx">
  159. <wd-button size="small" plain custom-class="cancel-btn" @click="handleCancelOrder(item)">
  160. 取消订单
  161. </wd-button>
  162. <wd-button size="small" plain custom-class="pay-btn" @click="handlePay(item)">
  163. 付款
  164. </wd-button>
  165. </view>
  166. </view>
  167. </view>
  168. </view>
  169. </view>
  170. <!-- 空状态 -->
  171. <view v-if="data && data.length === 0" class="flex flex-col items-center pt100rpx">
  172. <StatusTip tip="暂无抵扣券" />
  173. </view>
  174. </view>
  175. </view>
  176. </template>
  177. <style lang="scss" scoped>
  178. :deep(.use-btn) {
  179. border-color: #333 !important;
  180. color: #333 !important;
  181. border-radius: 32rpx !important;
  182. }
  183. :deep(.cancel-btn) {
  184. border-color: #999 !important;
  185. color: #999 !important;
  186. border-radius: 32rpx !important;
  187. }
  188. :deep(.pay-btn) {
  189. border-color: #333 !important;
  190. color: #333 !important;
  191. border-radius: 32rpx !important;
  192. }
  193. </style>