reportGenerationStatus.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. const RUNNING_STATE = 0
  2. const SUCCESS_STATE = 1
  3. const FAILED_STATE = -1
  4. function toNumber(value) {
  5. if (value === '' || value === null || value === undefined) return undefined
  6. const numeric = Number(value)
  7. return Number.isNaN(numeric) ? undefined : numeric
  8. }
  9. function toReportId(value) {
  10. if (value === '' || value === null || value === undefined) return undefined
  11. if (typeof value === 'string') return value
  12. if (typeof value === 'number' && Number.isFinite(value)) return String(value)
  13. return undefined
  14. }
  15. function pickReportId(source) {
  16. if (source === null || source === undefined) return undefined
  17. if (typeof source === 'number' || typeof source === 'string') return toReportId(source)
  18. if (typeof source !== 'object') return undefined
  19. const direct = toReportId(source.reportId ?? source.id)
  20. if (direct !== undefined) return direct
  21. for (const key of ['data', 'dto', 'info']) {
  22. const nested = pickReportId(source[key])
  23. if (nested !== undefined) return nested
  24. }
  25. return undefined
  26. }
  27. function extractReportId(payload) {
  28. return pickReportId(payload)
  29. }
  30. function normalizeGenerationStatus(payload = {}) {
  31. const source = payload && typeof payload === 'object' ? payload : {}
  32. const state = toNumber(source.state)
  33. return {
  34. reportId: extractReportId(source) ?? '',
  35. state: state === undefined ? RUNNING_STATE : state,
  36. status: source.status || '',
  37. errorMessage: source.errorMessage || ''
  38. }
  39. }
  40. function applyGenerationStatus(payload = {}) {
  41. const generation = normalizeGenerationStatus(payload)
  42. if (generation.state === FAILED_STATE) {
  43. return {
  44. ...generation,
  45. title: '报告生成失败',
  46. subtitle: '',
  47. description: generation.errorMessage || '失败原因:网络延迟',
  48. errorMessage: generation.errorMessage || '网络延迟',
  49. polling: false,
  50. actionText: '重新生成',
  51. imageKey: 'fail'
  52. }
  53. }
  54. if (generation.state === SUCCESS_STATE) {
  55. return {
  56. ...generation,
  57. title: '报告生成成功',
  58. subtitle: '',
  59. description: '报告已生成完成,你可以去我的PREILL报告查阅报告结果。',
  60. errorMessage: '',
  61. polling: false,
  62. actionText: '返回',
  63. imageKey: 'success'
  64. }
  65. }
  66. return {
  67. ...generation,
  68. title: '报告正在生成中~',
  69. subtitle: '预计所需时间1小时左右',
  70. description: '我们会在报告生成完成后提示你,你可以去我的PREILL报告查阅报告结果。',
  71. errorMessage: '',
  72. polling: true,
  73. actionText: '返回',
  74. imageKey: 'success'
  75. }
  76. }
  77. function replaceFirstPage(currentList, nextList) {
  78. void currentList
  79. return Array.isArray(nextList) ? nextList.slice() : []
  80. }
  81. function shouldResumePolling(reportId, generation = {}) {
  82. return Boolean(reportId && normalizeGenerationStatus(generation).state === RUNNING_STATE)
  83. }
  84. function reconcileStatusQueryError(currentGeneration = {}) {
  85. return applyGenerationStatus(normalizeGenerationStatus(currentGeneration))
  86. }
  87. function createStatusRequestState() {
  88. return {
  89. isPageVisible: false,
  90. statusVisibilityToken: 0,
  91. statusRequestSeq: 0,
  92. statusActiveRequestId: 0,
  93. statusRequestInFlight: false
  94. }
  95. }
  96. function setStatusPageVisible(state, visible) {
  97. if (!state || state.isPageVisible === visible) return state ? state.statusVisibilityToken : 0
  98. state.isPageVisible = visible
  99. if (!visible) {
  100. state.statusVisibilityToken += 1
  101. state.statusActiveRequestId = 0
  102. state.statusRequestInFlight = false
  103. }
  104. return state.statusVisibilityToken
  105. }
  106. function beginStatusRequest(state) {
  107. if (!state || !state.isPageVisible || state.statusRequestInFlight) return null
  108. state.statusRequestSeq += 1
  109. state.statusActiveRequestId = state.statusRequestSeq
  110. state.statusRequestInFlight = true
  111. return {
  112. requestId: state.statusActiveRequestId,
  113. visibilityToken: state.statusVisibilityToken
  114. }
  115. }
  116. function shouldApplyStatusResponse(state, meta) {
  117. return Boolean(
  118. state
  119. && meta
  120. && state.isPageVisible
  121. && state.statusRequestInFlight
  122. && state.statusActiveRequestId === meta.requestId
  123. && state.statusVisibilityToken === meta.visibilityToken
  124. )
  125. }
  126. function finishStatusRequest(state, meta) {
  127. if (!state || !meta) return
  128. if (state.statusActiveRequestId === meta.requestId) {
  129. state.statusActiveRequestId = 0
  130. state.statusRequestInFlight = false
  131. }
  132. }
  133. function createListRefreshState() {
  134. return {
  135. refreshGeneration: 0,
  136. inFlightPageRequests: {}
  137. }
  138. }
  139. function beginListRefresh(state) {
  140. if (!state) return 0
  141. state.refreshGeneration += 1
  142. return state.refreshGeneration
  143. }
  144. function createListRequestMeta(generation, page) {
  145. return { generation, page }
  146. }
  147. function shouldApplyListResponse(currentGeneration, meta) {
  148. return Boolean(meta && currentGeneration === meta.generation)
  149. }
  150. function beginListPageRequest(state, generation, page) {
  151. if (!state) return null
  152. const key = `${generation}:${page}`
  153. if (state.inFlightPageRequests[key]) return null
  154. const meta = { generation, page, key }
  155. state.inFlightPageRequests[key] = true
  156. return meta
  157. }
  158. function finishListPageRequest(state, meta) {
  159. if (!state || !meta || !meta.key) return
  160. delete state.inFlightPageRequests[meta.key]
  161. }
  162. module.exports = {
  163. RUNNING_STATE,
  164. SUCCESS_STATE,
  165. FAILED_STATE,
  166. extractReportId,
  167. normalizeGenerationStatus,
  168. applyGenerationStatus,
  169. replaceFirstPage,
  170. shouldResumePolling,
  171. reconcileStatusQueryError,
  172. createStatusRequestState,
  173. setStatusPageVisible,
  174. beginStatusRequest,
  175. shouldApplyStatusResponse,
  176. finishStatusRequest,
  177. createListRefreshState,
  178. beginListRefresh,
  179. createListRequestMeta,
  180. shouldApplyListResponse,
  181. beginListPageRequest,
  182. finishListPageRequest
  183. }