CommonCategoryBlocks.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  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. :titleLevel="category.textLevel"
  13. :showMore="category.showMore !== false"
  14. :moreText="category.moreText || '更多'"
  15. @clickMore="category.morePage"
  16. />
  17. <!--预制块-->
  18. <template v-if="category.type === 'CalendarBlock'">
  19. <CalendarBlock v-bind="category.blockProps" />
  20. </template>
  21. <template v-else-if="category.type === 'StatsBlock'">
  22. <StatsBlock v-bind="category.blockProps" />
  23. </template>
  24. <template v-else-if="category.type === 'MapBlock'">
  25. <MapCategoryBlock v-bind="category.blockProps" />
  26. </template>
  27. <template v-else-if="category.type === 'AudioBlock'">
  28. <AudioBlock v-bind="category.blockProps" />
  29. </template>
  30. <template v-else-if="category.type === 'RichBlock'">
  31. <RichBlock v-bind="category.blockProps" />
  32. </template>
  33. <!--通用列表-->
  34. <SimplePageContentLoader v-else-if="category.data" :loader="category.data" >
  35. <FlexCol>
  36. <template v-if="category.type === 'simple-article'">
  37. <FlexCol :margin="[10, 0]">
  38. <Box2LineRightShadow
  39. v-for="(item, i) in category.data.content.value"
  40. :key="i"
  41. :title="item.title"
  42. :titleBox="item.titleBox"
  43. :desc="item.desc"
  44. :tags="(item.bottomTags as string[])"
  45. @click="category.detailsPage(item)"
  46. />
  47. </FlexCol>
  48. </template>
  49. <template v-else-if="category.type === 'large-image'">
  50. <FlexCol>
  51. <Box2LineLargeImageUserShadow
  52. v-for="(item, i) in category.data.content.value"
  53. titleColor="title-text"
  54. fixSize
  55. title1
  56. :key="i"
  57. :title="item.title"
  58. :titleBox="Boolean(item.titleBox)"
  59. :desc="item.desc"
  60. :image="item.image"
  61. :tags="(item.bottomTags as string[])"
  62. @click="category.detailsPage(item)"
  63. />
  64. </FlexCol>
  65. </template>
  66. <template v-else-if="category.type === 'large-image2'">
  67. <scroll-view scroll-x>
  68. <FlexRow>
  69. <Box2LineLargeImageUserShadow
  70. v-for="(item, i) in category.data.content.value"
  71. classNames="width-2-3 mr-2"
  72. titleColor="title-text"
  73. fixSize
  74. title1
  75. :key="i"
  76. :title="item.title"
  77. :titleBox="Boolean(item.titleBox)"
  78. :desc="item.desc"
  79. :image="item.image"
  80. :tags="(item.bottomTags as string[])"
  81. @click="category.detailsPage(item)"
  82. />
  83. </FlexRow>
  84. </scroll-view>
  85. </template>
  86. <template v-else-if="category.type === 'horizontal-large'">
  87. <scroll-view scroll-x>
  88. <view class="pb-3 pt-3 d-flex flex-row overflow-visible align-stretch">
  89. <Box2LineLargeImageUserShadow
  90. v-for="(item, i) in category.data.content.value"
  91. classNames="width-2-3 mr-2"
  92. titleColor="title-text"
  93. title1
  94. fixSize
  95. :key="i"
  96. :title="item.title"
  97. :titleBox="Boolean(item.titleBox)"
  98. :desc="item.desc"
  99. :image="item.thumbnail || item.image"
  100. :tags="(item.bottomTags as string[])"
  101. @click="category.detailsPage(item)"
  102. />
  103. </view>
  104. </scroll-view>
  105. </template>
  106. <template v-else-if="category.type === 'large-grid2'">
  107. <FlexRow wrap align="stretch" justify="space-between" overflow="visible">
  108. <Box2LineLargeImageUserShadow
  109. v-for="(item, i) in category.data.content.value"
  110. titleColor="title-text"
  111. width="calc(50% - 10rpx)"
  112. fixSize
  113. :key="i"
  114. :title="item.title"
  115. :titleBox="Boolean(item.titleBox)"
  116. :desc="item.desc"
  117. :image="item.image"
  118. :tags="(item.bottomTags as string[])"
  119. @click="category.detailsPage(item)"
  120. />
  121. </FlexRow>
  122. </template>
  123. <template v-else-if="category.type === 'small-grid2'">
  124. <FlexRow wrap justify="space-between" align="stretch">
  125. <Grid4Item
  126. v-for="(tab, k) in category.data.content.value"
  127. :key="k"
  128. :title="tab.title"
  129. :image="tab.thumbnail || tab.image"
  130. classNames="half"
  131. @click="category.detailsPage(tab)"
  132. />
  133. </FlexRow>
  134. </template>
  135. <template v-else-if="category.type === 'small-grid'">
  136. <FlexCol :gap="10" align="center">
  137. <Grid4Item
  138. v-for="(tab, k) in category.data.content.value"
  139. :key="k"
  140. :title="tab.title"
  141. :image="tab.thumbnail || tab.image"
  142. classNames="full"
  143. @click="category.detailsPage(tab)"
  144. />
  145. </FlexCol>
  146. </template>
  147. <template v-else-if="category.type === 'simple-text'">
  148. <FlexCol>
  149. <Box2LineImageRightShadow
  150. v-for="(item, i) in category.data.content.value"
  151. titleColor="title-text"
  152. :border="false"
  153. fixSize
  154. :key="i"
  155. :title="item.title"
  156. :titleBox="Boolean(item.titleBox)"
  157. :desc="item.desc"
  158. :showImage="false"
  159. :tags="(item.bottomTags as string[])"
  160. />
  161. </FlexCol>
  162. </template>
  163. <template v-else-if="category.type === 'article'">
  164. <Box2LineImageRightShadow
  165. v-for="(item, i) in category.data.content.value"
  166. titleColor="title-text"
  167. fixSize
  168. wideImage
  169. :key="i"
  170. :title="item.title"
  171. :titleBox="Boolean(item.titleBox)"
  172. :desc="item.desc"
  173. :image="item.image"
  174. :tags="(item.bottomTags as string[])"
  175. @click="category.detailsPage(item)"
  176. />
  177. </template>
  178. <template v-else>
  179. <Box2LineImageRightShadow
  180. v-for="(item, i) in category.data.content.value"
  181. titleColor="title-text"
  182. fixSize
  183. :key="i"
  184. :title="item.title"
  185. :titleBox="Boolean(item.titleBox)"
  186. :desc="item.desc"
  187. :image="item.image"
  188. :tags="(item.bottomTags as string[])"
  189. @click="category.detailsPage(item)"
  190. />
  191. </template>
  192. </FlexCol>
  193. </SimplePageContentLoader>
  194. </FlexCol>
  195. </FlexCol>
  196. </template>
  197. <script setup lang="ts">;
  198. import { computed, onMounted, watch, type PropType } from 'vue';
  199. import CommonContent, { GetContentListItem, GetContentListParams } from '@/api/CommonContent';
  200. import { navCommonDetail, navCommonList, navigateToAutoContent, resolveCommonContentGetPageDetailUrlAuto, resolveCommonContentSolveProps } from '../common/CommonContent';
  201. import { useSimpleDataLoader } from '@/common/composeabe/SimpleDataLoader';
  202. import { navTo } from '@/components/utils/PageAction';
  203. import HomeTitle from '@/pages/parts/HomeTitle.vue';
  204. import SimplePageContentLoader from '@/common/components/SimplePageContentLoader.vue';
  205. import Box2LineImageRightShadow from '@/pages/parts/Box2LineImageRightShadow.vue';
  206. import Box2LineRightShadow from '@/pages/parts/Box2LineRightShadow.vue';
  207. import FlexCol from '@/components/layout/FlexCol.vue';
  208. import FlexRow from '@/components/layout/FlexRow.vue';
  209. import CalendarBlock from '@/pages/travel/calendar/block.vue';
  210. import Box2LineLargeImageUserShadow from '@/pages/parts/Box2LineLargeImageUserShadow.vue';
  211. import StatsBlock from '@/pages/blocks/StatsBlock.vue';
  212. import MapCategoryBlock from '@/pages/blocks/MapBlock.vue';
  213. import Image from '@/components/basic/Image.vue';
  214. import AppCofig from '@/common/config/AppCofig';
  215. import Grid4Item from '@/pages/parts/Grid4Item.vue';
  216. import type { CategoryDefine } from './CommonCategoryBlocks';
  217. import { CommonCategoryDynamicDataSerializedApi, doGetDynamicListDataParams, type IHomeCommonCategoryDynamicDataDetailContent } from './CommonCategoryDynamicData';
  218. import AudioBlock from '@/pages/blocks/AudioBlock.vue';
  219. import { toast } from '@/components/utils/DialogAction';
  220. import { doDynamicNavDetails } from '../common/CommonListPage';
  221. import { doCallDynamicFunction } from './CommonCategoryDynamicEvax';
  222. import RichBlock from '@/pages/blocks/RichBlock.vue';
  223. const props = defineProps({
  224. /**
  225. * 分类定义
  226. */
  227. categoryDefine: {
  228. type: Array as PropType<CategoryDefine[]>,
  229. default: () => [],
  230. },
  231. /**
  232. * 父级数据
  233. */
  234. parentData: {
  235. type: Object as PropType<any>,
  236. default: () => {},
  237. },
  238. });
  239. const categoryDatas = computed(() => props.categoryDefine.map(item => {
  240. if (!item.content)
  241. return {
  242. ...item,
  243. detailsPage: () => {},
  244. morePage: () => {
  245. if (item.morePage?.startsWith('dynamic:'))
  246. doDynamicNavDetails(item.morePage.substring(8), {}, props.parentData);
  247. else if (item.morePage)
  248. navTo(item.morePage, {});
  249. },
  250. data: null,
  251. };
  252. return {
  253. ...item,
  254. detailsPage: (dataItem: GetContentListItem) => {
  255. const id = dataItem.id;
  256. let modelId = 0;
  257. let mainBodyColumnId : string|number|number[]|undefined = undefined;
  258. switch (item.data.type) {
  259. case 'commonContent':
  260. case 'serializedApi': {
  261. const params = doGetDynamicListDataParams(item.data);
  262. modelId = params.modelId;
  263. mainBodyColumnId = params.mainBodyColumnId;
  264. break;
  265. }
  266. }
  267. const params = { id, mainBodyColumnId, modelId };
  268. if (item.detailsPage) {
  269. if (item.detailsPage === 'disabled')
  270. return;
  271. else if (item.detailsPage === 'byContent')
  272. navigateToAutoContent(dataItem, params);
  273. else if (typeof item.detailsPage === 'string' && item.detailsPage.startsWith('dynamic:')) {
  274. doDynamicNavDetails(item.detailsPage.substring(8), dataItem, props.parentData);
  275. return;
  276. }
  277. else
  278. navTo(item.detailsPage, params);
  279. } else {
  280. navCommonDetail(params);
  281. }
  282. },
  283. morePage: () => {
  284. if (item.morePage === 'disabled') {
  285. return;
  286. } else if (item.morePage) {
  287. navTo(item.morePage, {});
  288. } else {
  289. let modelId = 0;
  290. let mainBodyColumnId : string|number|number[]|undefined = undefined;
  291. switch (item.data.type) {
  292. case 'commonContent':
  293. case 'serializedApi': {
  294. const params = doGetDynamicListDataParams(item.data);
  295. modelId = params.modelId;
  296. mainBodyColumnId = params.mainBodyColumnId;
  297. break;
  298. }
  299. }
  300. if (item.morePage?.startsWith('dynamic:')) {
  301. doCallDynamicFunction(item.morePage.substring(8), {
  302. sourceData: {
  303. main: {},
  304. customData: {},
  305. },
  306. });
  307. return;
  308. }
  309. navCommonList({
  310. title: item.title,
  311. mainBodyColumnId: mainBodyColumnId,
  312. modelId: modelId,
  313. detailsPage: item.detailsPage,
  314. dataSolve: item.dataSolve || [],
  315. itemType: item.itemType,
  316. })
  317. }
  318. },
  319. data: useSimpleDataLoader(async () => {
  320. let res : any[] = [];
  321. const params = new GetContentListParams();
  322. switch (item.data.type) {
  323. case 'commonContent': {
  324. params.setModelId(item.data.params.modelId);
  325. if (item.data?.otherParams)
  326. params.setSelfValues(item.data.otherParams);
  327. if (item.data.params?.mainBodyColumnId)
  328. params.setMainBodyColumnId(item.data.params.mainBodyColumnId);
  329. res = (await CommonContent
  330. .getContentList(params, 1, item.count || 4))
  331. .list;
  332. break;
  333. }
  334. case 'serializedApi': {
  335. if (item.data.params?.mainBodyColumnId)
  336. params.setMainBodyColumnId(item.data.params.mainBodyColumnId);
  337. if (item.data?.otherParams)
  338. params.setSelfValues(item.data.otherParams);
  339. res = (await CommonCategoryDynamicDataSerializedApi(item.data)
  340. .getContentList(params, 1, item.count || 4))
  341. .list;
  342. break;
  343. }
  344. case 'detailContent': {
  345. const data = item.data as IHomeCommonCategoryDynamicDataDetailContent;
  346. res = [ await CommonContent.getContentDetail(data.params!.id, undefined, data.params!.modelId || undefined) ];
  347. break;
  348. }
  349. case 'parentKey': {
  350. if (!props.parentData)
  351. throw new Error('父级数据未设置');
  352. res = props.parentData[item.data.key];
  353. break;
  354. }
  355. case 'staticData': {
  356. res = item.data.data;
  357. break;
  358. }
  359. case 'request': {
  360. res = (await CommonContent.request(
  361. item.data.url,
  362. {
  363. page: 1,
  364. pageSize: item.count || 4,
  365. ...item.data.querys,
  366. },
  367. {
  368. method: item.data.method,
  369. data: item.data.otherParams,
  370. },
  371. '',
  372. undefined,
  373. )).data as unknown as any[];
  374. break;
  375. }
  376. default:
  377. throw new Error(`未实现的动态数据接口 ${(item.data as any).type}`);
  378. }
  379. return resolveCommonContentSolveProps(res, item.dataSolve || []);
  380. }, false)
  381. }
  382. }));
  383. function loadCategoryDatas() {
  384. categoryDatas.value.forEach(item => {
  385. if (item.data)
  386. item.data.loadData(undefined, true);
  387. })
  388. }
  389. watch(categoryDatas, loadCategoryDatas);
  390. onMounted( loadCategoryDatas);
  391. </script>