index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. <template>
  2. <view class="home-container page-home d-flex flex-col bg-base">
  3. <Image
  4. innerClass="main-banner position-absolute"
  5. width="100%"
  6. src="https://mncdn.wenlvti.net/app_static/minnan/images/home/BackgroundBanner5.jpg"
  7. mode="widthFix"
  8. />
  9. <view class="content d-flex flex-col wing-l">
  10. <!-- 分栏 -->
  11. <view class="shadow-base radius-l bg-base p-3">
  12. <view
  13. class="main-banner-box mb-25"
  14. @click="navTo('introduction')"
  15. >
  16. <text class="title">世界闽南文化交流中心</text>
  17. <text>闽南文化生态保护区(厦门市)</text>
  18. <view class="more">
  19. <text>&nbsp;</text>
  20. </view>
  21. <Image
  22. innerClass="footer"
  23. src="https://mncdn.wenlvti.net/app_static/minnan/images/home/MainBanner2.png"
  24. mode="widthFix"
  25. />
  26. </view>
  27. <view class="position-relative d-flex flex-row flex-wrap justify-between mt-25 row-gap-sss">
  28. <HomeButton
  29. title="文化常识"
  30. icon="https://mncdn.wenlvti.net/app_static/minnan/images/home/IconMap.png"
  31. bg="https://mncdn.wenlvti.net/app_static/minnan/images/home/ButtonMapBg.png"
  32. @click="navTo('/pages/introduction/explore')"
  33. />
  34. <HomeButton
  35. title="文化资讯"
  36. icon="https://mncdn.wenlvti.net/app_static/minnan/images/home/IconDoc.png"
  37. @click="navTo('/pages/introduction/news')"
  38. />
  39. <HomeButton
  40. title="文化遗产"
  41. icon="https://mncdn.wenlvti.net/app_static/minnan/images/home/IconIch.png"
  42. @click="navTo('/pages/introduction/inhert')"
  43. />
  44. <HomeButton
  45. title="创新发展"
  46. icon="https://mncdn.wenlvti.net/app_static/minnan/images/home/IconReserch.png"
  47. @click="navTo('/pages/research/index')"
  48. />
  49. <HomeButton
  50. title="交流传播"
  51. icon="https://mncdn.wenlvti.net/app_static/minnan/images/home/IconArtifact.png"
  52. @click="navTo('/pages/introduction/recommend-news')"
  53. />
  54. <HomeButton
  55. title="乐游厦门"
  56. icon="https://mncdn.wenlvti.net/app_static/minnan/images/home/IconDiscover.png"
  57. @click="navTo('/pages/introduction/travel')"
  58. />
  59. </view>
  60. <view class="position-relative d-flex flex-row flex-wrap justify-between mt-3">
  61. <Box1AudioPlay
  62. class="w-100"
  63. :title="indexAudioPlayer.currentTitle.value"
  64. :image="indexAudioPlayer.currentItem?.value?.image"
  65. :playState="indexAudioPlayer.isPlaying.value"
  66. :playTime="indexAudioPlayer.timeString.value"
  67. @playPauseClick="indexAudioPlayer.playpause"
  68. @arrowClick="handleGoAudioList"
  69. @nextClick="indexAudioPlayer.next"
  70. @prevClick="indexAudioPlayer.prev"
  71. @click="handleGoAudioList"
  72. />
  73. </view>
  74. </view>
  75. <!-- 数据统计 -->
  76. <SimplePageContentLoader :loader="statsLoader">
  77. <view v-if="statsLoader.content.value" class="d-flex flex-col justify-center mt-3 pt-3 pb-3 bg-light-page radius-base">
  78. <view class="d-flex flex-col">
  79. <StatsText
  80. :title="statsLoader.content.value[0].title"
  81. :data="statsLoader.content.value[0].datas"
  82. :type="statsLoader.content.value[0].type"
  83. />
  84. <view class="p-2">
  85. <HorizontalScrollText :text="statsText1" :fontSize="26" color="text.second" :outerStyle="{ height: '40rpx' }" />
  86. </view>
  87. </view>
  88. <view class="border-top-light-primary pt-2 mt-3"></view>
  89. <view class="d-flex flex-col">
  90. <StatsText
  91. :title="statsLoader.content.value[1].title"
  92. :data="statsLoader.content.value[1].datas"
  93. :type="statsLoader.content.value[1].type"
  94. />
  95. <view class="p-2">
  96. <HorizontalScrollText :text="statsText2" :fontSize="26" color="text.second" :outerStyle="{ height: '40rpx' }" />
  97. </view>
  98. </view>
  99. <view class="border-top-light-primary pt-2 mt-3"></view>
  100. <StatsText
  101. :title="statsLoader.content.value[2].title"
  102. :data="statsLoader.content.value[2].datas"
  103. :type="statsLoader.content.value[2].type"
  104. />
  105. <view class="border-top-light-primary pt-2 mt-3"></view>
  106. <StatsText
  107. :title="statsLoader.content.value[3].title"
  108. :data="statsLoader.content.value[3].datas"
  109. :type="statsLoader.content.value[3].type"
  110. />
  111. <view class="border-top-light-primary pt-2 mt-3"></view>
  112. <StatsText
  113. :title="statsLoader.content.value[4].title"
  114. :data="statsLoader.content.value[4].datas"
  115. :type="statsLoader.content.value[4].type"
  116. />
  117. </view>
  118. </SimplePageContentLoader>
  119. <!-- 文化地图 -->
  120. <HomeTitle title="文化地图" />
  121. <view class="position-relative radius-l overflow-hidden">
  122. <map
  123. id="map"
  124. class="w-100 height-400"
  125. :markers="mapLoader.content.value || []"
  126. :enable-zoom="false"
  127. :enable-scroll="false"
  128. :scale="15"
  129. @click="navTo('/pages/inhert/map/index', { tab: mapTab })"
  130. />
  131. <scroll-view class="map-tags position-absolute" :scroll-x="true">
  132. <view class="tag-bar d-flex flex-row flex-nowrap">
  133. <view :class="mapTab == 1 ? 'active' : ''" @click="mapTab=1">
  134. <text class="iconfont icon-read" />
  135. 非遗项目
  136. </view>
  137. <view :class="mapTab == 2 ? 'active' : ''" @click="mapTab=2">
  138. <text class="iconfont icon-task-trip" />
  139. 非遗传习所
  140. </view>
  141. <view :class="mapTab == 3 ? 'active' : ''" @click="mapTab=3">
  142. <text class="iconfont icon-task-buliding" />
  143. 文物古迹
  144. </view>
  145. <view :class="mapTab == 4 ? 'active' : ''" @click="mapTab=4">
  146. <text class="iconfont icon-place" />
  147. 传统村落
  148. </view>
  149. <view :class="mapTab == 5 ? 'active' : ''" @click="mapTab=5">
  150. <text class="iconfont icon-task-environment-3" />
  151. 闽南文化景区
  152. </view>
  153. </view>
  154. </scroll-view>
  155. </view>
  156. <!-- 精彩推荐 -->
  157. <HomeTitle title="精彩推荐" />
  158. <SimplePageContentLoader :loader="recommendLoader">
  159. <view class="d-flex flex-row justify-between flex-wrap">
  160. <view
  161. v-for="(tab, k) in recommendLoader.content.value"
  162. :key="k"
  163. class="grid4-item position-relative mb-3"
  164. @click="handleGoDetails(tab)"
  165. >
  166. <text
  167. class="tag bg-mask-white color-primary radius-l p-1 position-absolute size-s text-lines-1"
  168. >
  169. {{ tab.title }}
  170. </text>
  171. <Image
  172. width="100%"
  173. :height="250"
  174. :radius="15"
  175. :src="tab.thumbnail || tab.image || AppCofig.defaultImage"
  176. mode="aspectFit"
  177. />
  178. </view>
  179. </view>
  180. </SimplePageContentLoader>
  181. </view>
  182. </view>
  183. <Tabbar :current="0" />
  184. </template>
  185. <script setup lang="ts">
  186. import { ref, watch } from 'vue';
  187. import { onShareTimeline, onShareAppMessage } from '@dcloudio/uni-app';
  188. import { navTo } from '@/components/utils/PageAction';
  189. import { useSimpleDataLoader } from '@/common/composeabe/SimpleDataLoader';
  190. import { useSimpleListAudioPlayer } from '@/common/composeabe/SimpleAudioPlayer';
  191. import { navHomePageMiniCommonListGo } from '@/pages/article/common/CommonContent';
  192. import CommonContent, { GetContentListParams } from '@/api/CommonContent';
  193. import UnmoveableContent from '@/api/inheritor/UnmoveableContent';
  194. import SeminarContent from '@/api/inheritor/SeminarContent';
  195. import ProjectsContent from '@/api/inheritor/ProjectsContent';
  196. import AppCofig from '@/common/config/AppCofig';
  197. import VillageApi from '@/api/inhert/VillageApi';
  198. import ScenicSpotContent from '@/api/fusion/ScenicSpotContent';
  199. import IndexContent from '@/api/introduction/IndexContent';
  200. import StatsText, { type StatsTextItem } from '../parts/StatsText.vue';
  201. import HomeTitle from '@/pages/parts/HomeTitle.vue';
  202. import Tabbar from '@/common/components/tabs/Tabbar.vue';
  203. import Box1AudioPlay from '@/pages/parts/Box1AudioPlay.vue';
  204. import SimplePageContentLoader from "@/common/components/SimplePageContentLoader.vue";
  205. import HorizontalScrollText from '@/components/typography/HorizontalScrollText.vue';
  206. import Image from '@/components/basic/Image.vue';
  207. import HomeButton from '../parts/HomeButton.vue';
  208. const mapCtx = uni.createMapContext('map');
  209. const mapTab = ref(1);
  210. const mapLoader = useSimpleDataLoader(async () => {
  211. let list ;
  212. switch (mapTab.value) {
  213. default:
  214. case 1:
  215. list = (await ProjectsContent.getContentList(new GetContentListParams(), 1, 6)).list
  216. break;
  217. case 2:
  218. list = (await SeminarContent.getContentList(new GetContentListParams(), 1, 6)).list
  219. break;
  220. case 3:
  221. list = (await UnmoveableContent.getContentList(new GetContentListParams(), 1, 6)).list
  222. break;
  223. case 4:
  224. list = (await VillageApi.getVallageList()).slice(1, 10)
  225. break;
  226. case 5:
  227. list = (await ScenicSpotContent.getContentList(new GetContentListParams(), 1, 6)).list
  228. break;
  229. }
  230. const res = list.map((p) => {
  231. return {
  232. ...p,
  233. id: p.id,
  234. longitude: Number(p.longitude),
  235. latitude: Number(p.latitude),
  236. iconPath: p.thumbnail,
  237. width: 40,
  238. height: 40,
  239. };
  240. });
  241. mapCtx.includePoints({
  242. points: res.map(p => {
  243. if (!p.longitude || !p.latitude) {
  244. p.longitude = AppCofig.defaultLonLat[0];
  245. p.latitude = AppCofig.defaultLonLat[1];
  246. }
  247. return {
  248. latitude: p.latitude,
  249. longitude: p.longitude,
  250. }
  251. }),
  252. padding: [20, 20, 20, 20],
  253. });
  254. return res;
  255. }, true, undefined, true);
  256. watch(mapTab, () => mapLoader.loadData(undefined, true));
  257. const indexAudioPlayer = useSimpleListAudioPlayer(async () => {
  258. return (await CommonContent.getContentList(new GetContentListParams()
  259. .setModelId(5)
  260. .setMainBodyColumnId(321)
  261. , 1, 10)).list.sort((a, b) => -1).map((p) => {
  262. return {
  263. id: p.id,
  264. title: p.title,
  265. image: p.thumbnail || p.image,
  266. src: p.audio as string,
  267. }
  268. });
  269. })
  270. function handleGoAudioList() {
  271. navTo('/pages/inhert/language/list')
  272. }
  273. const recommendLoader = useSimpleDataLoader(async () => {
  274. const list = [];
  275. list.push(...(await ProjectsContent.getContentList(new GetContentListParams(), 1, 6)).list.map((p) => {
  276. p.itemType = 'intangible';
  277. return p;
  278. }));
  279. list.push(...(await CommonContent.getContentList(new GetContentListParams()
  280. .setModelId(1)
  281. , 1, 6)).list.map((p) => {
  282. p.itemType = p.type == GetContentListParams.TYPE_VIDEO ? 'video' : 'artifact';
  283. return p;
  284. }));
  285. return list;
  286. });
  287. const statsText1 = ref('');
  288. const statsText2 = ref('');
  289. const statsLoader = useSimpleDataLoader(async () => {
  290. const data = (await IndexContent.getStats());
  291. let sumInheritor = 0;
  292. let sumProject = 0;
  293. const topLevelProject = data.ichData.find((p: any) => p.level_text == '人类非遗')?.total || 0;
  294. const secondLevelProject = data.ichData.find((p: any) => p.level_text == '国家级')?.total || 0;
  295. const thirdLevelProject = data.ichData.find((p: any) => p.level_text == '省级')?.total || 0;
  296. const forthLevelProject = data.ichData.find((p: any) => p.level_text == '市级')?.total || 0;
  297. const topLevelInheritor = data.inheritorData.find((p: any) => p.level_text == '国家级')?.total || 0;
  298. const secondLevelInheritor = data.inheritorData.find((p: any) => p.level_text == '省级')?.total || 0;
  299. const thirdLevelInheritor = data.inheritorData.find((p: any) => p.level_text == '市级')?.total || 0;
  300. const projects = (data.ichData as any[]).filter((p: any) => [ '人类非遗', '国家级', '省级', '市级' ].includes(p.level_text)).map((item: any) => {
  301. if (item.level_text != '人类非遗')
  302. sumProject += item.total;
  303. return {
  304. title: item.level_text,
  305. value: item.total,
  306. titleSuffix: '项',
  307. type: 'forth',
  308. onClick: () => navTo('/pages/inhert/intangible/list', { tab: 0, level: item.level }),
  309. } as StatsTextItem
  310. });
  311. const inheritors = data.inheritorData.filter((p: any) => [ '国家级', '省级', '市级' ].includes(p.title)).map((item: any) => {
  312. sumInheritor += item.total;
  313. return {
  314. title: item.title,
  315. value: item.total,
  316. titleSuffix: '人',
  317. type: 'normal',
  318. onClick: () => navTo('/pages/inhert/inheritor/list', { level: item.level }),
  319. }
  320. });
  321. statsText1.value = `目前厦门市非遗项目市级以上共有 ${sumProject} 项,其中:国家级 ${secondLevelProject} 项(含 ${topLevelProject} 项为人类非遗)、省级 ${thirdLevelProject} 项、市级 ${forthLevelProject} 项。`;
  322. statsText2.value = `目前厦门市非遗传承人市级以上共有 ${sumInheritor} 人,其中:国家级 ${topLevelInheritor} 人、省级 ${secondLevelInheritor} 人、市级 ${thirdLevelInheritor} 人。`;
  323. return [
  324. {
  325. title: '非遗项目',
  326. datas: projects
  327. },
  328. {
  329. title: '非遗传承人',
  330. datas: inheritors
  331. },
  332. {
  333. title: '非遗传习所',
  334. datas: data.ichCenter.map((item: any) => {
  335. return {
  336. title: item.title,
  337. value: item.total,
  338. titleSuffix: '处',
  339. type: 'normal',
  340. onClick: () => navTo('/pages/inhert/seminar/list', { region: item.id }),
  341. }
  342. }),
  343. },
  344. {
  345. title: '重要相关历史风貌区',
  346. datas: data.historyData.map((item: any) => {
  347. return {
  348. title: item.title,
  349. value: item.total,
  350. titleSuffix: '处',
  351. onClick: () => {
  352. switch (item.title) {
  353. case '世界文化遗产':
  354. navHomePageMiniCommonListGo({
  355. title: '世界文化遗产',
  356. modelId: 17,
  357. mainBodyColumnId: 310
  358. });
  359. break;
  360. case '传统村落':
  361. navTo('/pages/inhert/village/list');
  362. break;
  363. case '重点区域':
  364. navHomePageMiniCommonListGo({
  365. title: '重点区域',
  366. modelId: 17,
  367. mainBodyColumnId: 283
  368. });
  369. break;
  370. }
  371. },
  372. }
  373. }),
  374. },
  375. {
  376. title: '闽南文化重要相关文物古迹',
  377. type: 'none',
  378. datas: data.minnanCr.map((item: any) => {
  379. return {
  380. title: item.title,
  381. value: item.total,
  382. titleSuffix: '处',
  383. onClick: () => navTo('/pages/inhert/artifact/list', {
  384. level: item.level
  385. }),
  386. }
  387. }),
  388. },
  389. ]
  390. });
  391. function handleGoDetails(item: any) {
  392. switch (item.itemType) {
  393. case 'artifact':
  394. navTo('/pages/inhert/artifact/details', { id: item.id });
  395. break;
  396. case 'intangible':
  397. navTo('/pages/inhert/intangible/details', { id: item.id });
  398. break;
  399. case 'video':
  400. navTo('/pages/video/details', { id: item.id, modelId: item.modelId, mainBodyColumnId: item.mainBodyColumnId });
  401. break;
  402. default:
  403. navTo('/pages/article/details', { id: item.id, modelId: item.modelId, mainBodyColumnId: item.mainBodyColumnId });
  404. break;
  405. }
  406. }
  407. onShareTimeline(() => {
  408. return {};
  409. })
  410. onShareAppMessage(() => {
  411. return {};
  412. })
  413. </script>
  414. <style lang="scss">
  415. .page-home {
  416. .main-banner {
  417. top: -150rpx;
  418. }
  419. .content {
  420. margin-top: 260rpx;
  421. }
  422. .map-tags {
  423. left: 0;
  424. top: 0;
  425. padding: 15rpx 0;
  426. font-size: 25rpx;
  427. .tag-bar {
  428. padding: 0 20rpx;
  429. view {
  430. display: flex;
  431. flex-direction: row;
  432. align-items: center;
  433. flex-shrink: 0;
  434. border-radius: 40rpx;
  435. padding: 10rpx 15rpx;
  436. background-color: #f7f3e8;
  437. color: #d9492e;
  438. margin-right: 10rpx;
  439. .iconfont {
  440. margin-right: 8rpx;
  441. }
  442. &.active {
  443. background-color: #d9492e;
  444. color: #f7f3e8;
  445. }
  446. }
  447. }
  448. }
  449. .grid4-item {
  450. width: 320rpx;
  451. .tag {
  452. top: 2rpx;
  453. right: 2rpx;
  454. z-index: 20;
  455. }
  456. }
  457. .main-banner-box {
  458. position: relative;
  459. display: flex;
  460. flex-direction: column;
  461. overflow: hidden;
  462. border-radius: 15rpx;
  463. background: linear-gradient(180deg, #E5CDAB 0%, #F0E3D6 100%), #F7F3E8;
  464. padding: 20rpx;
  465. font-family: "SongtiSCBlack";
  466. color: #432A04;
  467. .title {
  468. font-size: 40rpx;
  469. }
  470. text {
  471. font-size: 35rpx;
  472. margin-top: 10rpx;
  473. }
  474. .more {
  475. margin-top: 30rpx;
  476. padding: 10rpx 18rpx;
  477. width: 180rpx;
  478. &.badge {
  479. background-image: url('https://mncdn.wenlvti.net/app_static/minnan/images/home/MainBanner.png');
  480. background-size: 100% auto;
  481. background-repeat: no-repeat;
  482. }
  483. text {
  484. font-family: initial;
  485. font-size: 30rpx;
  486. }
  487. }
  488. .footer {
  489. position: absolute;
  490. right: -30rpx;
  491. bottom: -10rpx;
  492. width: 350rpx;
  493. z-index: 2;
  494. height: auto;
  495. }
  496. }
  497. }
  498. </style>