index.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. <template>
  2. <view class="detail-page">
  3. <view v-if="detail" class="detail">
  4. <view v-if="title" class="detail-title">
  5. {{ title }}
  6. </view>
  7. <view v-if="createTime || author" class="detail-meta">
  8. <view v-if="createTime">{{ createTime }}</view>
  9. <view v-if="author" class="detail-author">{{ author }}</view>
  10. </view>
  11. <view v-if="drugName" class="detail-drug"> 关联药品:{{ drugName }} </view>
  12. <view v-if="content" class="detail-content">
  13. <mpHtml :content="content" />
  14. </view>
  15. </view>
  16. <view v-else class="empty">暂无内容</view>
  17. </view>
  18. </template>
  19. <script setup lang="ts">
  20. import { computed, ref } from 'vue'
  21. import { onLoad } from '@dcloudio/uni-app'
  22. import mpHtml from 'mp-html/dist/uni-app/components/mp-html/mp-html'
  23. import { getWXLoginCode } from '@/lib/wechatService'
  24. import {
  25. getAlbumByIdApi,
  26. getArticleByIdApi,
  27. shareAlbumByIdApi,
  28. shareArticleByIdApi,
  29. } from '@/services/modules/information'
  30. import type { AlbumPageNewItem, ArticleItem } from '@/services/modules/information/type'
  31. type DetailType = 'academic' | 'album'
  32. type DetailItem = ArticleItem | AlbumPageNewItem
  33. interface PageQuery {
  34. id?: string
  35. type?: DetailType
  36. shareUserId?: string
  37. packageId?: string
  38. remark?: string
  39. }
  40. const detail = ref<DetailItem>()
  41. const detailType = ref<DetailType>('academic')
  42. const isArticle = computed(() => detailType.value === 'academic')
  43. const articleDetail = computed(() => detail.value as ArticleItem | undefined)
  44. const albumDetail = computed(() => detail.value as AlbumPageNewItem | undefined)
  45. const title = computed(() => {
  46. return isArticle.value ? articleDetail.value?.title : albumDetail.value?.xcmc
  47. })
  48. const createTime = computed(() => detail.value?.createTime?.slice(0, 10) || '')
  49. const author = computed(() => {
  50. return isArticle.value ? articleDetail.value?.author : albumDetail.value?.createUser || ''
  51. })
  52. const drugName = computed(() => {
  53. if (isArticle.value) return ''
  54. return albumDetail.value?.glypName || albumDetail.value?.glyp || ''
  55. })
  56. const content = computed(() => {
  57. const html = isArticle.value ? articleDetail.value?.content : albumDetail.value?.wb
  58. return formatRichText(html || '')
  59. })
  60. onLoad((query) => {
  61. const pageQuery = query as PageQuery
  62. const { id, type = 'academic' } = pageQuery
  63. if (!id) return
  64. detailType.value = type
  65. void getDetail(id, pageQuery)
  66. })
  67. const getDetail = async (id: string, query: PageQuery): Promise<void> => {
  68. try {
  69. const { data } = await requestDetail(id, query)
  70. detail.value = data
  71. } catch (error) {
  72. console.error('get detail failed:', error)
  73. }
  74. }
  75. const requestDetail = async (id: string, query: PageQuery) => {
  76. const { shareUserId = '', packageId = '', remark = '' } = query
  77. if (!shareUserId || !packageId) {
  78. return detailType.value === 'academic' ? getArticleByIdApi(id) : getAlbumByIdApi(id)
  79. }
  80. let openUserId = ''
  81. try {
  82. const loginResult = await getWXLoginCode()
  83. openUserId = loginResult?.code || ''
  84. } catch (error) {
  85. console.error('get WeChat login code for shared information failed:', error)
  86. }
  87. const commonParams = {
  88. shareUserId,
  89. openUserId,
  90. type: 'open',
  91. packageId,
  92. sharePicUrl: '',
  93. remark,
  94. } as const
  95. return detailType.value === 'academic'
  96. ? shareArticleByIdApi({
  97. ...commonParams,
  98. articleId: id,
  99. })
  100. : shareAlbumByIdApi({
  101. ...commonParams,
  102. id,
  103. })
  104. }
  105. const formatRichText = (html: string): string => {
  106. return html
  107. .replace(
  108. /<img\b(?![^>]*\bstyle=)/gi,
  109. '<img style="max-width:100%;height:auto;display:block;margin:20rpx 0;"'
  110. )
  111. .replace(
  112. /<video\b(?![^>]*\bstyle=)/gi,
  113. '<video style="width:100%;height:auto;display:block;margin:20rpx 0;"'
  114. )
  115. }
  116. </script>
  117. <style lang="scss" scoped>
  118. .detail-page {
  119. min-height: 100vh;
  120. background-color: #ffffff;
  121. }
  122. .detail {
  123. padding: 36rpx 30rpx 60rpx;
  124. }
  125. .detail-title {
  126. color: #222222;
  127. font-size: 42rpx;
  128. font-weight: 600;
  129. line-height: 1.45;
  130. }
  131. .detail-meta {
  132. margin-top: 18rpx;
  133. color: #999999;
  134. font-size: 26rpx;
  135. line-height: 1.5;
  136. }
  137. .detail-author {
  138. margin-top: 24rpx;
  139. }
  140. .detail-drug {
  141. margin-top: 24rpx;
  142. padding: 18rpx 20rpx;
  143. border-left: 6rpx solid #3b82f6;
  144. border-radius: 8rpx;
  145. background-color: #f5f8ff;
  146. color: #4b5563;
  147. font-size: 26rpx;
  148. line-height: 1.5;
  149. }
  150. .detail-content {
  151. margin-top: 34rpx;
  152. color: #333333;
  153. font-size: 31rpx;
  154. line-height: 1.8;
  155. word-break: break-word;
  156. }
  157. .empty {
  158. padding: 120rpx 30rpx;
  159. color: #999999;
  160. font-size: 28rpx;
  161. text-align: center;
  162. }
  163. </style>