ContentBlocks.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. <template>
  2. <!--通用内容首页小分块组件-->
  3. <FlexCol width="100%">
  4. <!-- 分类 -->
  5. <FlexCol
  6. v-for="(category,i) in categoryDatas" :key="i"
  7. :innerStyle="category.style"
  8. >
  9. <HomeTitle
  10. v-if="category.showTitle"
  11. :title="category.title"
  12. :showMore="category.showMore !== false"
  13. :showIcon="category.showIcon !== false"
  14. :showTopMargin="category.showTopMargin !== false"
  15. :icon="category.icon"
  16. :size="category.size || 'medium'"
  17. :subTitle="category.subTitle"
  18. :center="category.center"
  19. :moreText="category.moreText || '更多'"
  20. @moreClicked="category.morePage"
  21. >
  22. <template v-if="category.titleRightButtons" #right>
  23. <FlexRow align="center" gap="gap.md">
  24. <FrameButton
  25. v-for="item in category.titleRightButtons"
  26. :key="item.text"
  27. :text="item.text"
  28. :size="item.size"
  29. :primary="item.primary || false"
  30. @click="() => scriptEngine.execute(item.handler, getNodeContext(), { params: { item } })"
  31. />
  32. <Width :size="15" />
  33. </FlexRow>
  34. </template>
  35. </HomeTitle>
  36. <!--预制块-->
  37. <template v-if="category.type === 'RichBlock'">
  38. <RichBlock
  39. v-bind="category.blockProps"
  40. :scriptEngine="scriptEngine"
  41. :getNodeContext="getNodeContext"
  42. />
  43. </template>
  44. <!--通用列表-->
  45. <SimplePageContentLoader v-else-if="category.data" :loader="category.data" >
  46. <FlexCol>
  47. <template v-if="category.type === 'simple-article'">
  48. <FlexCol :margin="[10, 0]">
  49. <Box2LineImageRightShadow
  50. v-for="(item, i) in category.data.content.value"
  51. :key="i"
  52. :title="item.title"
  53. :titleBox="item.titleBox"
  54. :desc="item.desc"
  55. :tags="(item.bottomTags as string[])"
  56. :props="item.props"
  57. @click="category.detailsPage(item)"
  58. />
  59. </FlexCol>
  60. </template>
  61. <template v-else-if="category.type === 'large-image'">
  62. <FlexCol>
  63. <Box2LineLargeImageUserShadow
  64. v-for="(item, i) in category.data.content.value"
  65. titleColor="title-text"
  66. fixSize
  67. title1
  68. :key="i"
  69. :title="item.title"
  70. :titleBox="Boolean(item.titleBox)"
  71. :desc="item.desc"
  72. :image="item.image"
  73. :tags="(item.bottomTags as string[])"
  74. :props="item.props"
  75. @click="category.detailsPage(item)"
  76. />
  77. </FlexCol>
  78. </template>
  79. <template v-else-if="category.type === 'large-image2'">
  80. <scroll-view scroll-x>
  81. <FlexRow>
  82. <Box2LineLargeImageUserShadow
  83. v-for="(item, i) in category.data.content.value"
  84. :width="400"
  85. titleColor="title-text"
  86. fixSize
  87. title1
  88. :key="i"
  89. :title="item.title"
  90. :titleBox="Boolean(item.titleBox)"
  91. :desc="item.desc"
  92. :image="item.image"
  93. :tags="(item.bottomTags as string[])"
  94. :props="item.props"
  95. @click="category.detailsPage(item)"
  96. />
  97. </FlexRow>
  98. </scroll-view>
  99. </template>
  100. <template v-else-if="category.type === 'horizontal-large'">
  101. <scroll-view scroll-x>
  102. <FlexRow :padding="[20,0]" overflow="visible" align="stretch">
  103. <Box2LineLargeImageUserShadow
  104. v-for="(item, i) in category.data.content.value"
  105. :width="400"
  106. titleColor="title-text"
  107. title1
  108. fixSize
  109. :key="i"
  110. :title="item.title"
  111. :titleBox="Boolean(item.titleBox)"
  112. :desc="item.desc"
  113. :image="item.thumbnail || item.image"
  114. :tags="(item.bottomTags as string[])"
  115. :props="item.props"
  116. @click="category.detailsPage(item)"
  117. />
  118. </FlexRow>
  119. </scroll-view>
  120. </template>
  121. <template v-else-if="category.type === 'large-grid2'">
  122. <FlexRow wrap align="stretch" justify="space-between" overflow="visible">
  123. <Box2LineLargeImageUserShadow
  124. v-for="(item, i) in category.data.content.value"
  125. titleColor="title-text"
  126. width="calc(50% - 10rpx)"
  127. fixSize
  128. :key="i"
  129. :title="item.title"
  130. :titleBox="Boolean(item.titleBox)"
  131. :desc="item.desc"
  132. :image="item.image"
  133. :tags="(item.bottomTags as string[])"
  134. :props="item.props"
  135. @click="category.detailsPage(item)"
  136. />
  137. </FlexRow>
  138. </template>
  139. <template v-else-if="category.type === 'small-grid2'">
  140. <FlexRow wrap justify="space-between" align="stretch">
  141. <IndexRoundSimpleItem
  142. v-for="(tab, k) in category.data.content.value"
  143. :key="k"
  144. :item="{
  145. title: tab.title,
  146. image: tab.thumbnail || tab.image,
  147. }"
  148. :half="true"
  149. :props="tab.props"
  150. @click="category.detailsPage(tab)"
  151. />
  152. </FlexRow>
  153. </template>
  154. <template v-else-if="category.type === 'small-grid'">
  155. <FlexCol :gap="10" align="center">
  156. <IndexRoundSimpleItem
  157. v-for="(tab, k) in category.data.content.value"
  158. :key="k"
  159. :item="{
  160. title: tab.title,
  161. image: tab.thumbnail || tab.image,
  162. }"
  163. :half="false"
  164. :props="tab.props"
  165. :imageHeight="400"
  166. @click="category.detailsPage(tab)"
  167. />
  168. </FlexCol>
  169. </template>
  170. <template v-else-if="category.type === 'simple-text'">
  171. <FlexCol>
  172. <Box2LineImageRightShadow
  173. v-for="(item, i) in category.data.content.value"
  174. titleColor="title-text"
  175. :border="false"
  176. fixSize
  177. :key="i"
  178. :title="item.title"
  179. :titleBox="Boolean(item.titleBox)"
  180. :desc="item.desc"
  181. :showImage="false"
  182. :props="item.props"
  183. :tags="(item.bottomTags as string[])"
  184. />
  185. </FlexCol>
  186. </template>
  187. <template v-else-if="category.type === 'article'">
  188. <Box2LineImageRightShadow
  189. v-for="(item, i) in category.data.content.value"
  190. titleColor="title-text"
  191. fixSize
  192. wideImage
  193. :key="i"
  194. :title="item.title"
  195. :titleBox="Boolean(item.titleBox)"
  196. :desc="item.desc"
  197. :image="item.image"
  198. :tags="(item.bottomTags as string[])"
  199. :props="item.props"
  200. @click="category.detailsPage(item)"
  201. />
  202. </template>
  203. <template v-else-if="category.type === 'box-grid'">
  204. <FlexRow wrap justify="space-between" align="stretch">
  205. <IndexRoundBoxSimpleItem
  206. v-for="(tab, k) in category.data.content.value"
  207. :key="k"
  208. :item="tab"
  209. :iconSize="tab.iconSize"
  210. :props="tab.props"
  211. @click="category.detailsPage(tab)"
  212. />
  213. </FlexRow>
  214. </template>
  215. <template v-else>
  216. <Box2LineImageRightShadow
  217. v-for="(item, i) in category.data.content.value"
  218. titleColor="title-text"
  219. fixSize
  220. :key="i"
  221. :title="item.title"
  222. :titleBox="Boolean(item.titleBox)"
  223. :desc="item.desc"
  224. :image="item.image"
  225. :tags="(item.bottomTags as string[])"
  226. :props="item.props"
  227. @click="category.detailsPage(item)"
  228. />
  229. </template>
  230. </FlexCol>
  231. </SimplePageContentLoader>
  232. <text v-else>No Data</text>
  233. </FlexCol>
  234. </FlexCol>
  235. </template>
  236. <script setup lang="ts">;
  237. import { computed, onMounted, watch, type PropType } from 'vue';
  238. import { GetContentListItem } from '@/api/CommonContent';
  239. import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
  240. import { doLoadDynamicListData } from '../data/DynamicData';
  241. import type { ContentBlockDefine } from './ContentBlocks';
  242. import type { MiniScript } from '@/components/dynamic/minisc/MiniScript';
  243. import FlexCol from '@/components/layout/FlexCol.vue';
  244. import FlexRow from '@/components/layout/FlexRow.vue';
  245. import FrameButton from '@/common/components/FrameButton.vue';
  246. import HomeTitle from '@/common/components/parts/HomeTitle.vue';
  247. import SimplePageContentLoader from '@/components/loader/SimplePageContentLoader.vue';
  248. import RichBlock from '../blocks/RichBlock.vue';
  249. import Box2LineLargeImageUserShadow from '@/common/components/parts/Box2LineLargeImageUserShadow.vue';
  250. import Box2LineImageRightShadow from '@/common/components/parts/Box2LineImageRightShadow.vue';
  251. import IndexRoundSimpleItem from '@/common/components/parts/IndexRoundSimpleItem.vue';
  252. import Width from '@/components/layout/space/Width.vue';
  253. import IndexRoundBoxSimpleItem from '@/common/components/parts/IndexRoundBoxSimpleItem.vue';
  254. const props = defineProps({
  255. /**
  256. * 分类定义
  257. */
  258. categoryDefine: {
  259. type: Array as PropType<ContentBlockDefine[]>,
  260. default: () => [],
  261. },
  262. /**
  263. * 父级数据
  264. */
  265. parentData: {
  266. type: Object as PropType<any>,
  267. default: () => {},
  268. },
  269. scriptEngine: {
  270. type: Object as PropType<MiniScript>,
  271. default: () => {},
  272. },
  273. getNodeContext: {
  274. type: Function as PropType<() => Record<string, any>>,
  275. default: () => {},
  276. },
  277. });
  278. const categoryDatas = computed(() => props.categoryDefine.map(item => {
  279. if (!item.content)
  280. return {
  281. ...item,
  282. detailsPage: () => {},
  283. morePage: () => {
  284. if (item.onMoreClicked)
  285. props.scriptEngine.execute(item.onMoreClicked, props.getNodeContext(), {});
  286. },
  287. data: null,
  288. };
  289. return {
  290. ...item,
  291. detailsPage: (dataItem: GetContentListItem) => {
  292. if (item.onItemDetailClicked)
  293. props.scriptEngine.execute(item.onItemDetailClicked, props.getNodeContext(), { dataItem });
  294. },
  295. morePage: () => {
  296. if (item.onMoreClicked)
  297. props.scriptEngine.execute(item.onMoreClicked, props.getNodeContext(), {});
  298. },
  299. data: useSimpleDataLoader(async () => {
  300. let res : any[] = [];
  301. if (!item.content)
  302. return res;
  303. res = (await doLoadDynamicListData(
  304. item.content, 1, item.count || 4, '',
  305. props.scriptEngine,
  306. props.getNodeContext,
  307. )).list;
  308. if (item.onContentSolve)
  309. res = props.scriptEngine.execute(item.onContentSolve || '', props.getNodeContext(), { res }) as any;
  310. return res;
  311. }, false)
  312. }
  313. }));
  314. function loadCategoryDatas() {
  315. categoryDatas.value.forEach(item => {
  316. if (item.data)
  317. item.data.load(true);
  318. })
  319. }
  320. watch(categoryDatas, loadCategoryDatas);
  321. onMounted( loadCategoryDatas);
  322. </script>