index.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <template>
  2. <view class="web-view-page">
  3. <web-view v-if="url" :src="url" @message="handleMessage" />
  4. </view>
  5. </template>
  6. <script setup lang="ts">
  7. import { ref } from 'vue'
  8. import { onLoad } from '@dcloudio/uni-app'
  9. import { useSettlementSignStore } from '@/stores/modules/settlementSign'
  10. interface WebViewPageQuery {
  11. url?: string
  12. subjectLocation?: string
  13. signTraceId?: string
  14. }
  15. interface WebViewMessage {
  16. subjectLocation?: string
  17. signTraceId?: string
  18. success?: boolean
  19. status?: string
  20. [key: string]: unknown
  21. }
  22. interface WebViewMessageEvent {
  23. detail?: {
  24. data?: unknown
  25. }
  26. }
  27. const settlementSignStore = useSettlementSignStore()
  28. const url = ref('')
  29. const routeSubjectLocation = ref('')
  30. const routeSignTraceId = ref('')
  31. const showToast = (title: string) => {
  32. uni.showToast({
  33. title,
  34. icon: 'none',
  35. })
  36. }
  37. const safeDecodeURIComponent = (value: string) => {
  38. try {
  39. return decodeURIComponent(value)
  40. } catch (error) {
  41. console.error('decodeURIComponent error:', error)
  42. return value
  43. }
  44. }
  45. const normalizeMessageData = (event: WebViewMessageEvent): WebViewMessage => {
  46. const rawData = event.detail?.data
  47. const firstData = Array.isArray(rawData) ? rawData[0] : rawData
  48. if (!firstData) return {}
  49. if (typeof firstData === 'string') {
  50. try {
  51. return JSON.parse(firstData) as WebViewMessage
  52. } catch {
  53. return {
  54. status: firstData,
  55. }
  56. }
  57. }
  58. if (typeof firstData === 'object') {
  59. return firstData as WebViewMessage
  60. }
  61. return {}
  62. }
  63. const getStringValue = (value: unknown): string => {
  64. return typeof value === 'string' ? value.trim() : ''
  65. }
  66. const resolveSubjectLocation = (message: WebViewMessage): string => {
  67. const messageSubjectLocation = getStringValue(message.subjectLocation)
  68. const contextSubjectLocation = settlementSignStore.pendingSubjectLocation
  69. return messageSubjectLocation || routeSubjectLocation.value || contextSubjectLocation
  70. }
  71. const resolveSignTraceId = (message: WebViewMessage): string => {
  72. const messageSignTraceId = getStringValue(message.signTraceId)
  73. const contextSignTraceId = settlementSignStore.validContext?.signTraceId || ''
  74. return messageSignTraceId || routeSignTraceId.value || contextSignTraceId
  75. }
  76. const redirectToSettlementSignPage = (subjectLocation: string, signTraceId: string) => {
  77. if (!subjectLocation) {
  78. showToast('参数异常')
  79. return
  80. }
  81. const query = [`subjectLocationByUrl=${encodeURIComponent(subjectLocation)}`, `source=webMessage`]
  82. if (signTraceId) {
  83. query.push(`signTraceId=${encodeURIComponent(signTraceId)}`)
  84. }
  85. uni.redirectTo({
  86. url: `/pages-auth/settlement-channel-sign/index?${query.join('&')}`,
  87. })
  88. }
  89. const handleMessage = (event: WebViewMessageEvent) => {
  90. const message = normalizeMessageData(event)
  91. console.log('web-view message:', message)
  92. const subjectLocation = resolveSubjectLocation(message)
  93. const signTraceId = resolveSignTraceId(message)
  94. redirectToSettlementSignPage(subjectLocation, signTraceId)
  95. }
  96. onLoad((query: WebViewPageQuery) => {
  97. if (!query?.url) {
  98. showToast('签约地址不存在')
  99. uni.navigateBack({
  100. delta: 1,
  101. })
  102. return
  103. }
  104. url.value = safeDecodeURIComponent(query.url)
  105. routeSubjectLocation.value = query.subjectLocation || ''
  106. routeSignTraceId.value = query.signTraceId || ''
  107. })
  108. </script>
  109. <style lang="scss" scoped>
  110. .web-view-page {
  111. width: 100%;
  112. height: 100vh;
  113. }
  114. </style>