index.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. <template>
  2. <!-- 通用 OA web-view:发起 + 详情共用;结构对齐 start/webview -->
  3. <web-view v-if="src" :src="src" @message="onMessage" />
  4. </template>
  5. <script>
  6. import {
  7. buildOaDetailUrl,
  8. buildOaStartUrl,
  9. takeOaDetailTitle,
  10. takeOaStartTitle
  11. } from '../../../utils/oa-h5.js'
  12. import { forceRelogin, getToken } from '../../../utils/auth.js'
  13. import { fetchOaTemplateDetail } from '../../../utils/oa-api.js'
  14. const CLOSE_ACTIONS = new Set([
  15. 'oa-start-close',
  16. 'oa-start-cancel',
  17. 'oa-start-draft',
  18. 'oa-start-submitted',
  19. 'oa-detail-close',
  20. 'oa-detail-done',
  21. 'oa-detail-withdraw',
  22. 'oa-detail-restart'
  23. ])
  24. export default {
  25. data() {
  26. return { src: '', _closing: false }
  27. },
  28. onLoad(query) {
  29. if (!getToken()) {
  30. forceRelogin('请先登录')
  31. return
  32. }
  33. const instanceId = String((query && query.instanceId) || '')
  34. const taskId = String((query && query.taskId) || '')
  35. const mode = String((query && query.mode) || '') || 'view'
  36. const autoPrint = String((query && query.autoPrint) || '') === '1'
  37. const appId = String((query && query.appId) || '')
  38. const draftId = String((query && query.draftId) || '')
  39. const fromInstanceId = String((query && query.fromInstanceId) || '')
  40. let src = ''
  41. if (instanceId) {
  42. const cachedName = takeOaDetailTitle()
  43. if (cachedName) {
  44. uni.setNavigationBarTitle({ title: cachedName })
  45. }
  46. src = buildOaDetailUrl({ instanceId, taskId, mode, autoPrint })
  47. } else if (draftId || appId || fromInstanceId) {
  48. const cachedName = takeOaStartTitle()
  49. if (cachedName) {
  50. uni.setNavigationBarTitle({ title: cachedName })
  51. } else if (appId) {
  52. this.resolveTitle(appId)
  53. }
  54. src = buildOaStartUrl({ appId, draftId, fromInstanceId })
  55. } else {
  56. uni.showToast({ title: '参数错误', icon: 'none' })
  57. setTimeout(() => {
  58. uni.navigateBack({
  59. fail: () => {}
  60. })
  61. }, 400)
  62. return
  63. }
  64. if (!/\btoken=/.test(src)) {
  65. forceRelogin('请先登录')
  66. return
  67. }
  68. console.log('[oa webview] src=', src)
  69. this.src = src
  70. // H5:OA 页在 iframe 内,靠 postMessage 通知本页 uni.navigateBack
  71. // (微信小程序由 OA 内 wx.miniProgram.navigateBack,勿在此再退一层)
  72. // #ifdef H5
  73. this._onParentMessage = (e) => {
  74. const d = e && e.data
  75. if (!d || d.source !== 'zkxw-oa-h5') return
  76. this.navigateBackFromOa(d)
  77. }
  78. window.addEventListener('message', this._onParentMessage)
  79. // #endif
  80. },
  81. onUnload() {
  82. // #ifdef H5
  83. if (this._onParentMessage) {
  84. window.removeEventListener('message', this._onParentMessage)
  85. this._onParentMessage = null
  86. }
  87. // #endif
  88. },
  89. methods: {
  90. async resolveTitle(appId) {
  91. try {
  92. const detail = await fetchOaTemplateDetail(appId)
  93. const name = String(
  94. (detail && (detail.appName || detail.name)) || ''
  95. ).trim()
  96. if (name) uni.setNavigationBarTitle({ title: name })
  97. } catch (_) {
  98. /* 保留 pages.json 兜底标题 */
  99. }
  100. },
  101. navigateBackFromOa(payload) {
  102. if (this._closing) return
  103. const action = String((payload && payload.action) || '')
  104. if (action && !CLOSE_ACTIONS.has(action)) return
  105. // 复制重开:离开详情 webview 栈时,改开发起页(同页 redirect)
  106. if (action === 'oa-detail-restart') {
  107. const appId = String((payload && payload.appId) || '').trim()
  108. const fromInstanceId = String(
  109. (payload && (payload.fromInstanceId || payload.instanceId)) || ''
  110. ).trim()
  111. if (!appId && !fromInstanceId) return
  112. this._closing = true
  113. const q = []
  114. if (appId) q.push('appId=' + encodeURIComponent(appId))
  115. if (fromInstanceId) {
  116. q.push('fromInstanceId=' + encodeURIComponent(fromInstanceId))
  117. }
  118. uni.redirectTo({
  119. url: '/pages/oa/webview/index?' + q.join('&'),
  120. fail: () => {
  121. this._closing = false
  122. uni.navigateTo({
  123. url: '/pages/oa/webview/index?' + q.join('&'),
  124. fail: () => {
  125. this._closing = false
  126. }
  127. })
  128. }
  129. })
  130. return
  131. }
  132. this._closing = true
  133. const msg = String((payload && payload.message) || '').trim()
  134. if (msg) {
  135. uni.showToast({ title: msg, icon: 'none', duration: 1200 })
  136. }
  137. setTimeout(() => {
  138. uni.navigateBack({
  139. fail: () => {
  140. this._closing = false
  141. }
  142. })
  143. }, msg ? 400 : 0)
  144. },
  145. onMessage(e) {
  146. /* 微信:多在后退/销毁时触发;列表页 onShow 可刷新。勿再 navigateBack */
  147. console.log('[oa webview] message', e && e.detail)
  148. }
  149. }
  150. }
  151. </script>