details.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. <template>
  2. <FlexCol :padding="[0,0,50,0]">
  3. <SimplePageContentLoader :loader="loader">
  4. <template v-if="loader.content.value">
  5. <FlexCol :gap="20">
  6. <swiper
  7. v-if="loader.content.value.images.length > 0"
  8. circular
  9. :indicator-dots="true"
  10. :autoplay="true"
  11. :interval="3000"
  12. :duration="1000"
  13. :style="{ height: '500rpx' }"
  14. >
  15. <swiper-item v-for="(item, key) in loader.content.value.images" :key="key">
  16. <Image
  17. :src="item"
  18. width="100%"
  19. :height="500"
  20. :radius="20"
  21. mode="aspectFill"
  22. touchable
  23. @click="onPreviewImage(key)"
  24. />
  25. </swiper-item>
  26. </swiper>
  27. <Image
  28. v-else-if="loader.content.value.image"
  29. :radius="20"
  30. :src="loader.content.value.image"
  31. mode="widthFix"
  32. width="100%"
  33. />
  34. <FlexCol :padding="20" :gap="14">
  35. <H2>{{ loader.content.value.title }}</H2>
  36. <FlexRow>
  37. <Text v-if="loader.content.value.from" :text="`来源:${loader.content.value.from}`" fontConfig="subText" />
  38. <Text :text="DataDateUtils.formatDate(loader.content.value.publishAt, 'YYYY-MM-dd')" fontConfig="subText" />
  39. </FlexRow>
  40. </FlexCol>
  41. <FlexCol :padding="20" :radius="20">
  42. <Parse
  43. v-if="loader.content.value.content"
  44. :content="loader.content.value.content"
  45. />
  46. <Text v-if="emptyContent" fontConfig="subText">暂无简介</Text>
  47. </FlexCol>
  48. <!-- 推荐 -->
  49. <FlexCol v-if="recommendListLoader.content.value?.length" :padding="20">
  50. <H4>相关推荐</H4>
  51. <Box2LineImageRightShadow
  52. titleColor="black"
  53. v-for="item in recommendListLoader.content.value"
  54. :key="item.id"
  55. :image="item.thumbnail || item.image || AppCofig.defaultImage"
  56. :title="item.title"
  57. :desc="item.desc"
  58. :badge="(item.badge as string)"
  59. :wideImage="true"
  60. @click="goDetails(item.id)"
  61. />
  62. </FlexCol>
  63. <!-- 广告 -->
  64. <ad />
  65. </FlexCol>
  66. </template>
  67. </SimplePageContentLoader>
  68. </FlexCol>
  69. </template>
  70. <script setup lang="ts">
  71. import { computed } from "vue";
  72. import { useSimpleDataLoader } from "@/common/composeabe/SimpleDataLoader";
  73. import { useSimplePageContentLoader } from "@/common/composeabe/SimplePageContentLoader";
  74. import { useSwiperImagePreview } from "@/common/composeabe/SwiperImagePreview";
  75. import { useLoadQuerys } from "@/common/composeabe/LoadQuerys";
  76. import { navTo } from "@/components/utils/PageAction";
  77. import { onShareTimeline, onShareAppMessage } from "@dcloudio/uni-app";
  78. import { DataDateUtils } from "@imengyu/js-request-transform";
  79. import type { GetContentDetailItem } from "@/api/CommonContent";
  80. import SimplePageContentLoader from "@/common/components/SimplePageContentLoader.vue";
  81. import Parse from "@/components/display/parse/Parse.vue";
  82. import CommonContent, { GetContentListParams } from "@/api/CommonContent";
  83. import Box2LineImageRightShadow from "@/common/components/parts/Box2LineImageRightShadow.vue";
  84. import AppCofig from "@/common/config/AppCofig";
  85. import FlexCol from "@/components/layout/FlexCol.vue";
  86. import Image from "@/components/basic/Image.vue";
  87. import H4 from "@/components/typography/H4.vue";
  88. import Text from "@/components/basic/Text.vue";
  89. import H2 from "@/components/typography/H2.vue";
  90. import FlexRow from "@/components/layout/FlexRow.vue";
  91. const loader = useSimplePageContentLoader<
  92. GetContentDetailItem,
  93. { id: number }
  94. >(async (params) => {
  95. if (!params)
  96. throw new Error("!params");
  97. const res = await CommonContent.getContentDetail(params.id);
  98. //console.log(res);
  99. uni.setNavigationBarTitle({ title: res.title });
  100. return res;
  101. });
  102. const { onPreviewImage } = useSwiperImagePreview(() => loader.content.value?.images || [])
  103. const emptyContent = computed(() => (loader.content.value?.content || '').trim() === '')
  104. const recommendListLoader = useSimpleDataLoader(async () => {
  105. if (!querys.value.modelId)
  106. return []
  107. return (await CommonContent.getContentList(new GetContentListParams()
  108. .setModelId(querys.value.modelId)
  109. .setMainBodyColumnId(querys.value.mainBodyColumnId)
  110. .setSelfValues({
  111. mainBodyId: querys.value.mainBodyId,
  112. })
  113. , 1, 10)).list.filter((p) => p.id !== querys.value.id);
  114. });
  115. function goDetails(id: number) {
  116. navTo('/pages/article/details', {
  117. id,
  118. mainBodyColumnId: querys.value.mainBodyColumnId,
  119. modelId: querys.value.modelId,
  120. mainBodyId: querys.value.mainBodyId,
  121. });
  122. }
  123. const { querys } = useLoadQuerys({
  124. id: 0,
  125. mainBodyColumnId: 0,
  126. mainBodyId: 0,
  127. modelId: 0,
  128. }, (t) => loader.loadData(t));
  129. function getPageShareData() {
  130. if (!loader.content.value)
  131. return { title: '文章详情', imageUrl: '' }
  132. return {
  133. title: loader.content.value.title,
  134. imageUrl: loader.content.value.images[0],
  135. }
  136. }
  137. onShareTimeline(() => {
  138. return getPageShareData();
  139. })
  140. onShareAppMessage(() => {
  141. return getPageShareData();
  142. })
  143. </script>