details.vue 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. <template>
  2. <FlexCol :padding="[0,0,50,0]">
  3. <FlexCol position="absolute" :zIndex="100" :inset="{ l: 0, r: 0, t: 0 }">
  4. <StatusBarSpace />
  5. <NavBar
  6. :title="loader.content.value?.title || '文章详情'"
  7. leftButton="back"
  8. :leftButtonProps="{
  9. buttonStyle: {
  10. marginLeft: '20rpx',
  11. },
  12. shape: 'round-full',
  13. backgroundColor: 'background.primary',
  14. }"
  15. customBack
  16. @backPressed="handleBack"
  17. />
  18. </FlexCol>
  19. <SimplePageContentLoader :loader="loader">
  20. <template v-if="loader.content.value && loader.isLoaded.value">
  21. <FlexCol gap="gap.md">
  22. <swiper
  23. v-if="loader.content.value.images.length > 0"
  24. circular
  25. :indicator-dots="true"
  26. :autoplay="true"
  27. :interval="3000"
  28. :duration="1000"
  29. :style="{ height: '500rpx' }"
  30. >
  31. <swiper-item v-for="(item, key) in loader.content.value.images" :key="key">
  32. <view class="item">
  33. <Image
  34. :src="item"
  35. width="100%"
  36. :height="500"
  37. mode="aspectFill"
  38. @click="onPreviewImage(key)"
  39. />
  40. </view>
  41. </swiper-item>
  42. </swiper>
  43. <video
  44. v-else-if="loader.content.value.video"
  45. :src="loader.content.value.video"
  46. :style="{ width: '100%', height: '500rpx' }"
  47. />
  48. <Image
  49. v-else-if="loader.content.value.image"
  50. :src="loader.content.value.image"
  51. width="100%"
  52. mode="widthFix"
  53. />
  54. <FlexCol v-else>
  55. <StatusBarSpace />
  56. <Height height="40px" />
  57. </FlexCol>
  58. <FlexRow justify="space-between" padding="padding.md" >
  59. <FlexCol gap="gap.md">
  60. <H4 fontFamily="SongtiSCBlack" wrap :maxWidth="700" :lines="2">{{ loader.content.value.title }}</H4>
  61. <FlexRow gap="gap.md">
  62. <Text v-if="loader.content.value.keywords" color="text.second" :size="28">{{ loader.content.value.keywords.join(' ') }}</Text>
  63. <Text color="text.second" :size="28">{{ DataDateUtils.formatDate(loader.content.value.publishAt, 'YYYY-MM-dd') }}</Text>
  64. </FlexRow>
  65. </FlexCol>
  66. </FlexRow>
  67. <FlexRow :padding="[0,30,30,30]" gap="gap.lg">
  68. <ImageBlock3
  69. :src="loader.content.value.image"
  70. :imageWidth="80"
  71. :imageHeight="50"
  72. backgroundColor="transparent"
  73. @click="handleGoVillageDetails(loader.content.value.villageId)"
  74. >
  75. <template #desc>
  76. <FlexCol>
  77. <Text
  78. :text="`来源于:${loader.content.value.villageName}`"
  79. fontConfig="lightGoldTitle"
  80. fontSize="30"
  81. />
  82. <Text fontConfig="subText" fontSize="20">点此进入村(社区)主页了解更多</Text>
  83. </FlexCol>
  84. </template>
  85. </ImageBlock3>
  86. <Touchable align="center" gap="gap.md" @click.stop="handleGoUserDetails">
  87. <Avatar
  88. :url="loader.content.value.villageVolunteerAvatar"
  89. defaultAvatar="https://xy.wenlvti.net/app_static/images/village/PlaceholderVolunteerNew.png"
  90. size="50"
  91. radius="radius.md"
  92. />
  93. <Text class="size-ll color-title-text" :wrap="false" :maxWidth="100">投稿人:{{ loader.content.value.villageVolunteerName }}</Text>
  94. </Touchable>
  95. </FlexRow>
  96. <FlexCol :padding="30">
  97. <Parse
  98. v-if="loader.content.value.content"
  99. :content="loader.content.value.content"
  100. />
  101. <Parse
  102. v-if="loader.content.value.overview"
  103. :content="(loader.content.value.overview as string)"
  104. />
  105. <Text v-if="emptyContent">暂无简介</Text>
  106. <FlexRow gap="gap.md" align="center">
  107. <Icon icon="info" size="40" />
  108. <template v-if="true" >
  109. <Text fontConfig="subText" fontSize="fontSize.sm" text="本文章仅代表作者个人观点," />
  110. <Text fontConfig="subText" fontSize="fontSize.sm" bold text="暂未通过村(社区)审核" />
  111. </template>
  112. <Text v-else fontConfig="subText" text="本文章仅代表作者个人观点" />
  113. </FlexRow>
  114. </FlexCol>
  115. <!-- 推荐 -->
  116. <FlexCol v-if="recommendListLoader.content.value?.length" :padding="30">
  117. <H5 fontFamily="SongtiSCBlack">相关推荐</H5>
  118. <Box2LineImageRightShadow
  119. titleColor="title-text"
  120. v-for="item in recommendListLoader.content.value"
  121. :key="item.id"
  122. :image="item.image || AppCofig.defaultImage"
  123. :title="item.title"
  124. :desc="item.desc"
  125. :badge="item.villageName"
  126. :wideImage="true"
  127. @click="goDetails(item.id)"
  128. />
  129. </FlexCol>
  130. <Height :height="100" />
  131. <LikeFooter
  132. :content="loader.content.value"
  133. @refresh="loader.reload(); isChangedStatus=true"
  134. />
  135. </FlexCol>
  136. </template>
  137. </SimplePageContentLoader>
  138. </FlexCol>
  139. </template>
  140. <script setup lang="ts">
  141. import { computed, ref } from "vue";
  142. import { useSimpleDataLoader } from "@/components/composeabe/loader/SimpleDataLoader";
  143. import { useSwiperImagePreview } from "@/common/composeabe/SwiperImagePreview";
  144. import { useLoadQuerys } from "@/components/composeabe/LoadQuerys";
  145. import { backAndCallOnPageBack, navTo, back } from "@/components/utils/PageAction";
  146. import { onShareTimeline, onShareAppMessage } from "@dcloudio/uni-app";
  147. import { DataDateUtils } from "@imengyu/js-request-transform";
  148. import SimplePageContentLoader from "@/components/loader/SimplePageContentLoader.vue";
  149. import Parse from "@/components/display/parse/Parse.vue";
  150. import Box2LineImageRightShadow from "@/common/components/parts/Box2LineImageRightShadow.vue";
  151. import AppCofig from "@/common/config/AppCofig";
  152. import VillageInfoApi from "@/api/inhert/VillageInfoApi";
  153. import FlexRow from "@/components/layout/FlexRow.vue";
  154. import FlexCol from "@/components/layout/FlexCol.vue";
  155. import Image from "@/components/basic/Image.vue";
  156. import Text from "@/components/basic/Text.vue";
  157. import H5 from "@/components/typography/H5.vue";
  158. import H4 from "@/components/typography/H4.vue";
  159. import Avatar from "@/components/display/Avatar.vue";
  160. import Touchable from "@/components/feedback/Touchable.vue";
  161. import StatusBarSpace from "@/components/layout/space/StatusBarSpace.vue";
  162. import NavBar from "@/components/nav/NavBar.vue";
  163. import LikeFooter from "./components/LikeFooter.vue";
  164. import Height from "@/components/layout/space/Height.vue";
  165. import Icon from "@/components/basic/Icon.vue";
  166. import ImageBlock3 from "@/components/display/block/ImageBlock3.vue";
  167. const { onPreviewImage } = useSwiperImagePreview(() => loader.content.value?.images || []);
  168. const emptyContent = computed(() =>
  169. (loader.content.value?.content || '').trim() === ''
  170. && (loader.content.value?.overview as string || '').trim() === ''
  171. );
  172. const loader = useSimpleDataLoader(async () => {
  173. const res = await VillageInfoApi.getInfoForDiscover(querys.value.id);
  174. uni.setNavigationBarTitle({ title: res.title });
  175. console.log('加载信息', res);
  176. return res;
  177. }, false);
  178. const recommendListLoader = useSimpleDataLoader(async () => {
  179. return (await VillageInfoApi.getListForDiscover({ page: 1, pageSize: 5 }))
  180. .list
  181. .filter((p) => p.id !== querys.value.id);
  182. });
  183. const { querys } = useLoadQuerys({
  184. id: 0,
  185. }, (t) => loader.reload());
  186. const isChangedStatus = ref(false);
  187. function goDetails(id: number) {
  188. navTo('details', {
  189. id,
  190. });
  191. }
  192. function handleGoUserDetails(id: number) {
  193. navTo('/pages/home/village/volunteer/detail', { id: loader.content.value?.villageVolunteerId });
  194. }
  195. function handleGoVillageDetails(id: number) {
  196. backAndCallOnPageBack('goVillage', { id });
  197. }
  198. function handleBack() {
  199. if (isChangedStatus.value) {
  200. backAndCallOnPageBack('refresh', { needRefresh: true });
  201. return;
  202. }
  203. back();
  204. }
  205. function getPageShareData() {
  206. if (!loader.content.value)
  207. return { title: '文章详情', imageUrl: '' }
  208. return {
  209. title: loader.content.value.title,
  210. imageUrl: loader.content.value.images[0],
  211. }
  212. }
  213. onShareTimeline(() => {
  214. return getPageShareData();
  215. })
  216. onShareAppMessage(() => {
  217. return getPageShareData();
  218. })
  219. </script>