index.vue 17 KB

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