DetailTabPage.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <template>
  2. <!-- TAB分页的详情页 -->
  3. <view class="d-flex flex-col bg-base">
  4. <SimplePageContentLoader :loader="loader">
  5. <template v-if="loader.content.value">
  6. <view class="d-flex flex-col">
  7. <!-- 轮播大图 -->
  8. <ImageSwiper
  9. v-if="showHead"
  10. :images="loader.content.value.images"
  11. />
  12. <!-- 标题区域 -->
  13. <view class="d-flex flex-col mt-3 p-3">
  14. <slot name="title" :content="loader.content.value">
  15. <view class="d-flex flex-col">
  16. <view class="d-flex flex-row align-center">
  17. <text :class="'size-lll font-songti font-bold color-text-content flex-shrink-1 mr-2' + (loader.content.value.titleBox ? ' border-all-text' : '')">
  18. {{ loader.content.value.title }}
  19. </text>
  20. <slot name="titleEnd" :content="loader.content.value" />
  21. </view>
  22. <text class="size-base color-text-content-second mt-2">{{ loader.content.value.desc }}</text>
  23. <text v-if="loader.content.value.from" class="size-s color-text-content-second">来源:{{ loader.content.value.from }}</text>
  24. </view>
  25. </slot>
  26. <slot name="titleExtra" :content="loader.content.value" />
  27. </view>
  28. <!-- 内容切换标签 -->
  29. <view class="ml-2 mr-2">
  30. <Tabs
  31. :tabs="tabs"
  32. v-model:currentIndex="tabCurrentIndex"
  33. :autoScroll="true"
  34. :autoItemWidth="false"
  35. :defaultIndicatorWidth="130"
  36. class="top-tab"
  37. />
  38. </view>
  39. <view class="d-flex flex-col radius-l bg-light p-25 mt-3" style="min-height:70vh">
  40. <!-- 简介 -->
  41. <template v-if="tabCurrentId == 0">
  42. <Parse
  43. v-if="loader.content.value.intro"
  44. :content="loader.content.value.intro"
  45. :tagStyle="commonParserStyle"
  46. />
  47. <Parse
  48. v-if="loader.content.value.content"
  49. :content="loader.content.value.content"
  50. :tagStyle="commonParserStyle"
  51. />
  52. <text v-if="emptyContent">暂无简介</text>
  53. </template>
  54. <!-- 图片 -->
  55. <template v-else-if="tabCurrentId == 1">
  56. <slot name="imagesPrefix" />
  57. <ImageGrid
  58. :images="loader.content.value.images"
  59. :rowCount="2"
  60. :preview="true"
  61. imageHeight="200rpx"
  62. />
  63. </template>
  64. <!-- 视频 -->
  65. <template v-else-if="tabCurrentId == 2">
  66. <video
  67. v-if="loader.content.value.video"
  68. class="w-100 video"
  69. autoplay
  70. :poster="loader.content.value.image"
  71. :src="loader.content.value.video"
  72. controls
  73. />
  74. </template>
  75. <!-- 音频 -->
  76. <template v-else-if="tabCurrentId == 3">
  77. <video
  78. v-if="loader.content.value.audio"
  79. class="w-100 video"
  80. autoplay
  81. :poster="loader.content.value.image"
  82. :src="loader.content.value.audio"
  83. controls
  84. />
  85. </template>
  86. <!-- 其他tab -->
  87. <slot v-else name="extraTabs" :tabCurrentId="tabCurrentId" :content="loader.content.value" />
  88. </view>
  89. <ContentNote />
  90. </view>
  91. <LikeFooter :content="loader.content.value" />
  92. </template>
  93. </SimplePageContentLoader>
  94. </view>
  95. </template>
  96. <script setup lang="ts">
  97. import type { GetContentDetailItem } from "@/api/CommonContent";
  98. import { useSimplePageContentLoader } from "@/common/composeabe/SimplePageContentLoader";
  99. import { useLoadQuerys } from "@/common/composeabe/LoadQuerys";
  100. import { useTabControl, type TabControlItem } from "@/common/composeabe/TabControl";
  101. import SimplePageContentLoader from "@/common/components/SimplePageContentLoader.vue";
  102. import ImageGrid from "@/pages/parts/ImageGrid.vue";
  103. import ImageSwiper from "@/pages/parts/ImageSwiper.vue";
  104. import ContentNote from "@/pages/parts/ContentNote.vue";
  105. import commonParserStyle from "@/common/style/commonParserStyle";
  106. import { computed, type PropType, type Ref } from "vue";
  107. import Parse from "@/components/display/parse/Parse.vue";
  108. import Tabs from "@/components/nav/Tabs.vue";
  109. import LikeFooter from "@/pages/parts/LikeFooter.vue";
  110. const props = defineProps({
  111. load: {
  112. type: Function as PropType<(id: number, tabsArray: Ref<TabControlItem[]>) => Promise<GetContentDetailItem>>,
  113. default: null,
  114. },
  115. extraTabs: {
  116. type: Array as PropType<TabControlItem[]>,
  117. default: () => [],
  118. },
  119. showHead: {
  120. type: Boolean,
  121. default: true,
  122. },
  123. })
  124. const emit = defineEmits([
  125. "tabChange"
  126. ])
  127. const emptyContent = computed(() => {
  128. return !(loader.content.value?.intro as string || '').trim() && !(loader.content.value?.content || '').trim();
  129. })
  130. const loader = useSimplePageContentLoader<
  131. GetContentDetailItem,
  132. { id: number }
  133. >(async (params) => {
  134. if (!params)
  135. throw new Error("!params");
  136. const d = await props.load(params.id, tabsArray);
  137. tabsArray.value[1].visible = Boolean(d.images && d.images.length > 1);
  138. tabsArray.value[2].visible = Boolean(d.video);
  139. tabsArray.value[3].visible = Boolean(d.audio);
  140. if (d.title)
  141. uni.setNavigationBarTitle({ title: d.title });
  142. setTimeout(() => {
  143. if (emptyContent.value) {
  144. if (d.video)
  145. tabCurrentIndex.value = 1;
  146. else if (d.video)
  147. tabCurrentIndex.value = 2;
  148. }
  149. }, 200);
  150. return d;
  151. });
  152. const {
  153. tabCurrentId,
  154. tabCurrentIndex,
  155. tabsArray,
  156. tabs,
  157. } = useTabControl({
  158. tabs: [
  159. {
  160. id: 0,
  161. text: '简介',
  162. visible: true,
  163. },
  164. {
  165. id: 1,
  166. text: '图片',
  167. visible: true,
  168. },
  169. {
  170. id: 2,
  171. text: '视频',
  172. visible: true,
  173. },
  174. {
  175. id: 3,
  176. text: '音频',
  177. visible: true,
  178. },
  179. ...props.extraTabs,
  180. ],
  181. onTabChange(a, b) {
  182. emit("tabChange", a, b);
  183. },
  184. })
  185. useLoadQuerys({ id : 0 }, (p) => loader.loadData(p));
  186. defineExpose({
  187. getPageShareData() {
  188. const content = loader.content.value;
  189. if (!content)
  190. return {};
  191. const res = {
  192. title: content.title,
  193. imageUrl: content.image,
  194. };
  195. return res;
  196. }
  197. })
  198. </script>
  199. <style lang="scss">
  200. </style>