details.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. <template>
  2. <view class="video-details main bg-base pb-5">
  3. <SimplePageContentLoader :loader="loader">
  4. <template v-if="loader.content.value">
  5. <video
  6. v-if="loader.content.value.audio"
  7. class="video"
  8. autoplay
  9. :poster="loader.content.value.image"
  10. :src="loader.content.value.audio"
  11. controls
  12. />
  13. <video
  14. v-else-if="loader.content.value.video"
  15. class="video"
  16. autoplay
  17. :poster="loader.content.value.image"
  18. :src="loader.content.value.video"
  19. controls
  20. />
  21. <view class="d-flex flex-col">
  22. <view class="d-flex flex-col p-3">
  23. <view class="size-ll color-title-text">{{ loader.content.value.title }}</view>
  24. <view class="d-flex flex-row mt-2">
  25. <text class="size-s color-text-content-second">{{ DataDateUtils.formatDate(loader.content.value.publishAt, 'YYYY-MM-dd') }}</text>
  26. </view>
  27. </view>
  28. <view class="content radius-l bg-light p-3">
  29. <Parse :content="loader.content.value.content"/>
  30. <text v-if="emptyContent" class="size-s color-text-content-second">暂无简介</text>
  31. </view>
  32. <!-- 推荐视频 -->
  33. <view v-if="recommendListLoader.content.value?.length && querys.showRecommend" class="d-flex flex-col p-3">
  34. <text class="size-base text-bold mb-3">推荐视频</text>
  35. <Box2LineImageRightShadow
  36. class="w-100"
  37. titleColor="title-text"
  38. v-for="item in recommendListLoader.content.value"
  39. :key="item.id"
  40. :image="item.thumbnail || item.image"
  41. :title="item.title"
  42. :desc="item.desc"
  43. :tags="item.bottomTags"
  44. :wideImage="true"
  45. @click="goDetails(item.id)"
  46. />
  47. </view>
  48. </view>
  49. <ContentNote />
  50. <LikeFooter :content="loader.content.value">
  51. <template #left>
  52. <ArticleCorrect :content="loader.content.value" />
  53. </template>
  54. </LikeFooter>
  55. </template>
  56. </SimplePageContentLoader>
  57. </view>
  58. </template>
  59. <script setup lang="ts">
  60. import type { GetContentDetailItem } from "@/api/CommonContent";
  61. import { navTo } from "@/components/utils/PageAction";
  62. import { computed } from "vue";
  63. import { useLoadQuerys } from "@/common/composeabe/LoadQuerys";
  64. import { useSimpleDataLoader } from "@/common/composeabe/SimpleDataLoader";
  65. import { useSimplePageContentLoader } from "@/common/composeabe/SimplePageContentLoader";
  66. import { onShareAppMessage, onShareTimeline } from "@dcloudio/uni-app";
  67. import { DataDateUtils } from "@imengyu/js-request-transform";
  68. import NewsIndexContent from "@/api/news/NewsIndexContent";
  69. import SimplePageContentLoader from "@/common/components/SimplePageContentLoader.vue";
  70. import ContentNote from "../parts/ContentNote.vue";
  71. import Parse from "@/components/display/parse/Parse.vue";
  72. import CommonContent, { GetContentListParams } from "@/api/CommonContent";
  73. import Box2LineImageRightShadow from "../parts/Box2LineImageRightShadow.vue";
  74. import AppCofig from "@/common/config/AppCofig";
  75. import LikeFooter from "../parts/LikeFooter.vue";
  76. import ArticleCorrect from "../parts/ArticleCorrect.vue";
  77. const loader = useSimplePageContentLoader<
  78. GetContentDetailItem,
  79. { id: number }
  80. >(async (params) => {
  81. if (!params)
  82. throw new Error("!params");
  83. const res = await NewsIndexContent.getContentDetail(params.id);
  84. uni.setNavigationBarTitle({ title: res.title });
  85. return res;
  86. });
  87. const recommendListLoader = useSimpleDataLoader(async () => {
  88. if (!querys.value.modelId)
  89. return []
  90. return (await CommonContent.getContentList(new GetContentListParams()
  91. .setModelId(querys.value.modelId)
  92. .setMainBodyColumnId(querys.value.mainBodyColumnId)
  93. , 1, 10)).list
  94. .filter((p) => p.id !== querys.value.id)
  95. .map((p) => ({
  96. ...p,
  97. bottomTags: [
  98. p.mainBodyColumnName,
  99. p.levelText,
  100. ] as string[],
  101. }));
  102. });
  103. const emptyContent = computed(() => (loader.content.value?.content || '').trim() === '')
  104. function goDetails(id: number) {
  105. navTo('/pages/video/details', {
  106. id,
  107. mainBodyColumnId: querys.value.mainBodyColumnId,
  108. modelId: querys.value.modelId
  109. });
  110. }
  111. function getPageShareData() {
  112. if (!loader.content.value)
  113. return { title: '文章详情', imageUrl: '' }
  114. return {
  115. title: loader.content.value.title,
  116. imageUrl: loader.content.value.images[0],
  117. }
  118. }
  119. onShareTimeline(() => {
  120. return getPageShareData();
  121. })
  122. onShareAppMessage(() => {
  123. return getPageShareData();
  124. })
  125. const { querys } = useLoadQuerys({
  126. id: 0,
  127. mainBodyColumnId: 0,
  128. modelId: 0,
  129. showRecommend: true,
  130. }, (t) => loader.loadData(t));
  131. </script>
  132. <style lang="scss">
  133. .video-details {
  134. padding: 0;
  135. .nested-content {
  136. padding: 15rpx 25rpx;
  137. }
  138. video {
  139. width: 750rpx;
  140. }
  141. }
  142. </style>