details.vue 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. <template>
  2. <FlexCol backgroundColor="background.page">
  3. <FlexCol position="absolute" :top="0" :left="0" :right="0" :zIndex="100">
  4. <StatusBarSpace backgroundColor="transparent" />
  5. <NavBar leftButton="back" :iconProps="{ color: 'white' }" textColor="white" />
  6. </FlexCol>
  7. <SimplePageContentLoader :loader="loader">
  8. <template v-if="loader.content.value">
  9. <view class="d-flex flex-col">
  10. <ImageSwiper
  11. v-if="loader.content.value.images.length > 0"
  12. :images="loader.content.value.images"
  13. height="500rpx"
  14. />
  15. <Image
  16. v-else-if="loader.content.value.image"
  17. width="100%"
  18. height="500rpx"
  19. :radius="15"
  20. :src="loader.content.value.image"
  21. :defaultImage="AppCofig.defaultImage"
  22. mode="widthFix"
  23. />
  24. <view class="d-flex flex-col p-3">
  25. <view class="size-ll color-title-text">{{ loader.content.value.title }}</view>
  26. <view class="d-flex flex-row mt-2">
  27. <text v-if="loader.content.value.from" class="size-s color-text-content-second mr-2 ">来源:{{ loader.content.value.from }}</text>
  28. <text class="size-s color-text-content-second text-nowrap">{{ DataDateUtils.formatDate(loader.content.value.publishAt, 'YYYY-MM-dd') }}</text>
  29. </view>
  30. </view>
  31. <view v-if="archiveInfo.hasArchive" class="mt-3">
  32. <Box2LineImageRightShadow
  33. class="w-100"
  34. titleColor="title-text"
  35. title2
  36. :image="archiveInfo.archiveIcon"
  37. :title="loader.content.value.title"
  38. desc="点击查看完整文档"
  39. @click="goArchive(loader.content.value.id)"
  40. />
  41. </view>
  42. <view class="p-3 radius-ll bg-light mt-3">
  43. <Parse
  44. v-if="loader.content.value.content"
  45. :content="loader.content.value.content"
  46. />
  47. <text v-if="emptyContent">暂无简介</text>
  48. </view>
  49. <!-- 推荐 -->
  50. <view v-if="recommendListLoader.content.value?.length" class="d-flex flex-col p-3">
  51. <text class="size-base text-bold mb-3">相关推荐</text>
  52. <Box2LineImageRightShadow
  53. class="w-100"
  54. titleColor="title-text"
  55. v-for="item in recommendListLoader.content.value"
  56. :key="item.id"
  57. :image="item.thumbnail || item.image || AppCofig.defaultImage"
  58. :title="item.title"
  59. :desc="item.desc"
  60. :wideImage="true"
  61. @click="goDetails(item.id)"
  62. />
  63. </view>
  64. <ContentNote />
  65. <LikeFooter :content="loader.content.value">
  66. <template #left>
  67. <ArticleCorrect :content="loader.content.value" />
  68. </template>
  69. </LikeFooter>
  70. </view>
  71. </template>
  72. </SimplePageContentLoader>
  73. <Footer text="到底了~" />
  74. </FlexCol>
  75. </template>
  76. <script setup lang="ts">
  77. import type { GetContentDetailItem } from "@/api/CommonContent";
  78. import { onShareTimeline, onShareAppMessage } from "@dcloudio/uni-app";
  79. import { DataDateUtils } from "@imengyu/js-request-transform";
  80. import { useSimplePageContentLoader } from "@/common/composeabe/SimplePageContentLoader";
  81. import { useSwiperImagePreview } from "@/common/composeabe/SwiperImagePreview";
  82. import { useLoadQuerys } from "@/common/composeabe/LoadQuerys";
  83. import NewsIndexContent from "@/api/news/NewsIndexContent";
  84. import SimplePageContentLoader from "@/common/components/SimplePageContentLoader.vue";
  85. import ContentNote from "../parts/ContentNote.vue";
  86. import Parse from "@/components/display/parse/Parse.vue";
  87. import { computed } from "vue";
  88. import { useSimpleDataLoader } from "@/common/composeabe/SimpleDataLoader";
  89. import { navTo } from "@/components/utils/PageAction";
  90. import CommonContent, { GetContentListParams } from "@/api/CommonContent";
  91. import Box2LineImageRightShadow from "../parts/Box2LineImageRightShadow.vue";
  92. import AppCofig from "@/common/config/AppCofig";
  93. import LikeFooter from "../parts/LikeFooter.vue";
  94. import Image from "@/components/basic/Image.vue";
  95. import ArticleCorrect from "../parts/ArticleCorrect.vue";
  96. import ImageSwiper from "../parts/ImageSwiper.vue";
  97. import IconExcel from '@/components/images/files/excel.png';
  98. import IconPowerpoint from '@/components/images/files/powerpoint.png';
  99. import IconUnknown from '@/components/images/files/unknown.png';
  100. import IconWord from '@/components/images/files/word.png';
  101. import IconPdf from '@/components/images/files/pdf.png';
  102. import { StringUtils } from "@imengyu/imengyu-utils";
  103. import Icon from "@/components/basic/Icon.vue";
  104. import FlexCol from "@/components/layout/FlexCol.vue";
  105. import Footer from "@/components/display/Footer.vue";
  106. import NavBar from "@/components/nav/NavBar.vue";
  107. import StatusBarSpace from "@/components/layout/space/StatusBarSpace.vue";
  108. const loader = useSimplePageContentLoader<
  109. GetContentDetailItem,
  110. { id: number }
  111. >(async (params) => {
  112. if (!params)
  113. throw new Error("!params");
  114. const res = await NewsIndexContent.getContentDetail(params.id);
  115. //console.log(res);
  116. uni.setNavigationBarTitle({ title: res.title });
  117. return res;
  118. });
  119. const { onPreviewImage } = useSwiperImagePreview(() => loader.content.value?.images || [])
  120. const emptyContent = computed(() => (loader.content.value?.content || '').trim() === '')
  121. const archiveInfo = computed(() => {
  122. const hasArchive = Boolean(loader.content.value?.archives);
  123. let fileIcon = IconUnknown;
  124. const ext = StringUtils.path.getFileExt(loader.content.value?.archives || '');
  125. switch (ext) {
  126. case 'excel':
  127. case 'xls':
  128. case 'xlsx':
  129. fileIcon = IconExcel;
  130. break;
  131. case 'powerpoint':
  132. case 'ppt':
  133. case 'pptx':
  134. fileIcon = IconPowerpoint;
  135. break;
  136. case 'word':
  137. case 'docx':
  138. case 'doc':
  139. case 'txt':
  140. case 'rtf':
  141. fileIcon = IconWord;
  142. break;
  143. case 'pdf':
  144. fileIcon = IconPdf;
  145. break;
  146. }
  147. return {
  148. hasArchive,
  149. archiveIcon: hasArchive ? fileIcon : IconUnknown,
  150. }
  151. })
  152. const recommendListLoader = useSimpleDataLoader(async () => {
  153. if (!querys.value.modelId)
  154. return []
  155. return (await CommonContent.getContentList(new GetContentListParams()
  156. .setModelId(querys.value.modelId)
  157. .setMainBodyColumnId(querys.value.mainBodyColumnId)
  158. , 1, 10)).list
  159. .filter((p) => p.id !== querys.value.id)
  160. .map((p) => ({
  161. ...p,
  162. desc: `${p.from ? `来源:${p.from}` : ''}\n${p.desc || ''}`,
  163. }));
  164. });
  165. function goArchive(id: number) {
  166. navTo('/pages/document/details', {
  167. id,
  168. });
  169. }
  170. function goDetails(id: number) {
  171. navTo('/pages/article/details', {
  172. id,
  173. mainBodyColumnId: querys.value.mainBodyColumnId,
  174. modelId: querys.value.modelId
  175. });
  176. }
  177. const { querys } = useLoadQuerys({
  178. id: 0,
  179. mainBodyColumnId: 0,
  180. modelId: 0,
  181. }, (t) => loader.loadData(t));
  182. function getPageShareData() {
  183. if (!loader.content.value)
  184. return { title: '文章详情', imageUrl: '' }
  185. return {
  186. title: loader.content.value.title,
  187. imageUrl: loader.content.value.images[0],
  188. }
  189. }
  190. onShareTimeline(() => {
  191. return getPageShareData();
  192. })
  193. onShareAppMessage(() => {
  194. return getPageShareData();
  195. })
  196. </script>