index.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. <script setup lang="ts">
  2. import type { wxpay } from '@/api/globals'
  3. import router from '@/router'
  4. definePage({ name: 'smqjh-threePay', islogin: false, style: { navigationBarTitleText: '支付', navigationStyle: 'custom' } })
  5. const { token } = storeToRefs(useUserStore())
  6. const { tenantCode } = storeToRefs(useSysStore())
  7. const orderNumber = ref()
  8. onLoad((options: any) => {
  9. orderNumber.value = options.orderNumber
  10. tenantCode.value = options.tenantCode
  11. token.value = ''
  12. handleLogin(options.phone)
  13. console.log(options, '============options=======')
  14. })
  15. const priceInfo = ref<wxpay>()
  16. function handleLogin(phoneCode: string) {
  17. uni.showLoading({ mask: true })
  18. uni.login({
  19. provider: 'weixin',
  20. success: async (res) => {
  21. const data = await Apis.sys.auth({
  22. params: {
  23. grant_type: 'wechat',
  24. code: res.code,
  25. phoneCode,
  26. },
  27. })
  28. console.log(data, '============data=======')
  29. token.value = `Bearer ${data.data.access_token}`
  30. useUserStore().getUserInfo()
  31. handlePay()
  32. },
  33. complete: () => {
  34. uni.hideLoading()
  35. },
  36. })
  37. }
  38. async function handlePay() {
  39. const res = await useUserStore().handleCommonPayMent(orderNumber.value)
  40. priceInfo.value = res
  41. console.log(priceInfo.value, '=========================')
  42. }
  43. async function handleGoPay() {
  44. if (priceInfo.value?.payType !== 1) {
  45. try {
  46. await useUserStore().getWxCommonPayment(priceInfo.value as wxpay)
  47. router.push({ name: 'common-threePayRes', params: { price: String(priceInfo.value?.price), type: '1' } })
  48. }
  49. catch (error: any) {
  50. console.log(error, '=========================')
  51. router.push({ name: 'common-threePayRes', params: { price: String(priceInfo.value?.price), type: '0', error: error.errMsg } })
  52. // console.log(111)
  53. }
  54. }
  55. }
  56. // 倒计时:15分钟 = 900秒
  57. const COUNTDOWN_SECONDS = 15 * 60
  58. const countdown = ref(COUNTDOWN_SECONDS)
  59. const countdownTimer = ref<ReturnType<typeof setInterval> | null>(null)
  60. // 模块级变量:记录倒计时结束的时间戳,离页后回来可继续
  61. // 页面卸载(onUnload)时重置,保证下次进入是全新的15分钟
  62. let endTimestamp: number | null = null
  63. // 格式化为 MM:SS
  64. const countdownText = computed(() => {
  65. const m = Math.floor(countdown.value / 60).toString().padStart(2, '0')
  66. const s = (countdown.value % 60).toString().padStart(2, '0')
  67. return `${m}:${s}`
  68. })
  69. function updateCountdown() {
  70. if (!endTimestamp)
  71. return
  72. const remaining = Math.max(0, Math.ceil((endTimestamp - Date.now()) / 1000))
  73. countdown.value = remaining
  74. if (remaining <= 0) {
  75. stopCountdown()
  76. // TODO: 倒计时结束后的跳转逻辑
  77. router.push({ name: 'common-threePayRes', params: { price: String(priceInfo.value?.price), type: '0' } })
  78. }
  79. }
  80. function startCountdown() {
  81. // 首次进入:初始化结束时间戳
  82. if (!endTimestamp) {
  83. endTimestamp = Date.now() + COUNTDOWN_SECONDS * 1000
  84. }
  85. // 立即同步一次剩余时间(防止回来时短暂显示旧值)
  86. updateCountdown()
  87. stopCountdown()
  88. countdownTimer.value = setInterval(updateCountdown, 1000)
  89. }
  90. function stopCountdown() {
  91. if (countdownTimer.value) {
  92. clearInterval(countdownTimer.value)
  93. countdownTimer.value = null
  94. }
  95. }
  96. // 页面显示时启动/恢复倒计时(含首次进入和从其他页面返回)
  97. onShow(() => {
  98. startCountdown()
  99. })
  100. // 离开页面时暂停定时器,但保留 endTimestamp
  101. onHide(() => {
  102. stopCountdown()
  103. })
  104. // 页面卸载时清理,下次进入重新开始
  105. onUnload(() => {
  106. stopCountdown()
  107. endTimestamp = null
  108. })
  109. </script>
  110. <template>
  111. <view>
  112. <wd-navbar title="支付" :bordered="false" :z-index="99" safe-area-inset-top placeholder fixed />
  113. <view v-if="priceInfo" class="px20rpx pt20rpx">
  114. <view class="text-center text-48rpx text-#FF4A39">
  115. ¥{{ (priceInfo?.price / 100).toFixed(2) }}
  116. </view>
  117. <view class="mb20rpx mt24rpx text-center text-26rpx text-[#999]">
  118. 支付剩余时间:<text class="text-[#FF4A39] font-semibold">
  119. {{ countdownText }}
  120. </text>
  121. </view>
  122. <wd-button block @click="handleGoPay">
  123. 确认支付
  124. </wd-button>
  125. </view>
  126. </view>
  127. </template>
  128. <style lang="scss" scoped></style>