CommonCategoryBlocks.vue 14 KB

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