advert.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. <template>
  2. <view class="art-page art-page--advert">
  3. <view class="art-nav" :style="{ paddingTop: statusBar + 'px' }">
  4. <view class="art-nav-row">
  5. <view class="art-back" @tap="goBack">
  6. <text class="art-back-icon">←</text>
  7. </view>
  8. <text class="art-nav-title">{{ navTitle }}</text>
  9. <view class="art-nav-placeholder" />
  10. </view>
  11. </view>
  12. <web-view
  13. v-if="hasUrl"
  14. class="art-webview"
  15. :style="{ height: webViewHeight + 'px' }"
  16. :webview-styles="webviewStyles"
  17. :src="article.url"
  18. />
  19. <scroll-view
  20. v-else
  21. scroll-y
  22. class="art-scroll"
  23. :style="{ height: scrollHeight + 'px' }"
  24. >
  25. <view class="art-body" :style="{ paddingBottom: safeBottom + 'px' }">
  26. <view v-if="loading" class="art-state">
  27. <text class="art-state-txt">{{ copy.loading }}</text>
  28. </view>
  29. <view v-else class="art-card">
  30. <rich-text class="art-rich" :nodes="contentNodes" />
  31. </view>
  32. </view>
  33. </scroll-view>
  34. </view>
  35. </template>
  36. <script>
  37. import {
  38. fetchAdvertDetails,
  39. formatArticleRichContent,
  40. isExternalArticleUrl
  41. } from '@/features/article/article-gateway'
  42. export default {
  43. data() {
  44. return {
  45. statusBar: 0,
  46. scrollHeight: 600,
  47. webViewHeight: 600,
  48. safeBottom: 0,
  49. articleId: '',
  50. navTitle: '',
  51. loading: true,
  52. article: {},
  53. contentNodes: [],
  54. webviewStyles: {
  55. progress: {
  56. color: '#4a8cff'
  57. }
  58. }
  59. }
  60. },
  61. computed: {
  62. copy() {
  63. const t = this.$t.bind(this)
  64. return {
  65. loading: t('article.loading'),
  66. loadFailed: t('article.loadFailed')
  67. }
  68. },
  69. hasUrl() {
  70. return isExternalArticleUrl(this.article && this.article.url)
  71. }
  72. },
  73. onLoad(option) {
  74. const sys = uni.getSystemInfoSync()
  75. this.statusBar = sys.statusBarHeight || 0
  76. this.safeBottom = sys.safeAreaInsets ? sys.safeAreaInsets.bottom : 0
  77. const navH = this.statusBar + uni.upx2px(88)
  78. const bodyH = (sys.windowHeight || 667) - navH
  79. this.scrollHeight = bodyH
  80. this.webViewHeight = bodyH
  81. this.articleId = option.id || ''
  82. this.navTitle = this.copy.loading
  83. this.loadArticle()
  84. },
  85. methods: {
  86. goBack() {
  87. if (getCurrentPages().length > 1) {
  88. uni.navigateBack({ delta: 1 })
  89. } else {
  90. uni.switchTab({
  91. url: '/pages/index/index',
  92. fail: () => uni.reLaunch({ url: '/pages/index/index' })
  93. })
  94. }
  95. },
  96. async loadArticle() {
  97. if (!this.articleId) {
  98. this.loading = false
  99. this.$appKit.msg(this.copy.loadFailed)
  100. return
  101. }
  102. this.loading = true
  103. try {
  104. const data = await fetchAdvertDetails(this.articleId)
  105. this.article = data
  106. if (data.title) {
  107. this.navTitle = data.title
  108. }
  109. if (!this.hasUrl) {
  110. const rich = formatArticleRichContent(data.content, null, {
  111. hideImages: true
  112. })
  113. this.contentNodes = rich.html ? rich.html : rich.nodes
  114. }
  115. } catch (err) {
  116. this.$appKit.msg((err && err.message) || this.copy.loadFailed)
  117. } finally {
  118. this.loading = false
  119. }
  120. }
  121. }
  122. }
  123. </script>
  124. <style scoped>
  125. @import './article-shared.css';
  126. </style>