home.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. <template>
  2. <view class="home-container page-home d-flex flex-col bg-base">
  3. <image
  4. class="w-100 position-absolute"
  5. src="https://mncdn.wenlvti.net/app_static/minnan/images/home/BackgroundBanner5.jpg"
  6. mode="widthFix"
  7. />
  8. <view class="content d-flex flex-col wing-l">
  9. <!-- 分栏 -->
  10. <view class="shadow-l radius-l bg-base p-3">
  11. <view
  12. class="main-banner-box"
  13. @click="navTo('home/introduction')"
  14. >
  15. <text class="title">闽南文化生态保护区(厦门市)</text>
  16. <text>世界闽南文化交流中心</text>
  17. <view class="more">
  18. <text>查看详情</text>
  19. </view>
  20. <image
  21. class="footer"
  22. src="https://mncdn.wenlvti.net/app_static/minnan/images/home/MainBanner2.png"
  23. mode="widthFix"
  24. />
  25. </view>
  26. <view class="position-relative d-flex flex-row flex-wrap justify-between mt-3">
  27. <view
  28. v-for="(tab, k) in subTabs"
  29. :key="k"
  30. class="d-flex flex-column align-center width-1-4 mt-2 mb-2"
  31. @click="tab.onClick"
  32. >
  33. <image class="width-100" :src="tab.icon" mode="widthFix" />
  34. <text class="color-second-text mt-2 size-base text-align-center">{{ tab.name }}</text>
  35. </view>
  36. <Box1AudioPlay
  37. class="w-100 mt-3"
  38. :title="indexAudioPlayer.currentTitle.value"
  39. :image="indexAudioPlayer.currentItem?.value?.image"
  40. :playState="indexAudioPlayer.isPlaying.value"
  41. :playTime="indexAudioPlayer.timeString.value"
  42. @playPauseClick="indexAudioPlayer.playpause"
  43. @nextClick="indexAudioPlayer.next"
  44. @prevClick="indexAudioPlayer.prev"
  45. @click="handleGoAudioList"
  46. />
  47. </view>
  48. </view>
  49. <!-- 数据统计 -->
  50. <SimplePageContentLoader :loader="statsLoader">
  51. <view v-if="statsLoader.content.value" class="d-flex flex-col mt-3 pt-3 b-3 b-0order-all-light-light-primary">
  52. <view class="d-flex flex-row">
  53. <StatsText
  54. class="w-50 border-right-forth"
  55. width="calc(50%)"
  56. :title="statsLoader.content.value[0].title"
  57. :data="statsLoader.content.value[0].datas"
  58. />
  59. <StatsText
  60. class="w-50"
  61. width="calc(50%)"
  62. :title="statsLoader.content.value[1].title"
  63. :data="statsLoader.content.value[1].datas"
  64. />
  65. </view>
  66. <StatsText
  67. class="border-top-forth pt-2 mt-3"
  68. width="calc(33%)"
  69. :data="statsLoader.content.value[2].datas"
  70. />
  71. </view>
  72. </SimplePageContentLoader>
  73. <!-- 文化地图 -->
  74. <HomeTitle title="文化地图" />
  75. <view class="position-relative radius-l overflow-hidden">
  76. <map
  77. id="map"
  78. class="w-100 height-400"
  79. :markers="mapLoader.content.value || []"
  80. :enable-zoom="false"
  81. :enable-scroll="false"
  82. :scale="15"
  83. @click="navTo('inhert/map/index', { tab: mapTab })"
  84. />
  85. <scroll-view class="map-tags position-absolute" :scroll-x="true">
  86. <view class="tag-bar d-flex flex-row flex-nowrap">
  87. <view :class="mapTab == 1 ? 'active' : ''" @click="mapTab=1">
  88. <text class="iconfont icon-read" />
  89. 非遗项目
  90. </view>
  91. <view :class="mapTab == 2 ? 'active' : ''" @click="mapTab=2">
  92. <text class="iconfont icon-task-trip" />
  93. 非遗传习所
  94. </view>
  95. <view :class="mapTab == 3 ? 'active' : ''" @click="mapTab=3">
  96. <text class="iconfont icon-task-buliding" />
  97. 文物古迹
  98. </view>
  99. <view :class="mapTab == 4 ? 'active' : ''" @click="mapTab=4">
  100. <text class="iconfont icon-place" />
  101. 传统村落
  102. </view>
  103. <view :class="mapTab == 5 ? 'active' : ''" @click="mapTab=5">
  104. <text class="iconfont icon-task-environment-3" />
  105. 闽南文化景区
  106. </view>
  107. </view>
  108. </scroll-view>
  109. </view>
  110. <!-- 精彩推荐 -->
  111. <HomeTitle title="精彩推荐" />
  112. <SimplePageContentLoader :loader="recommendLoader">
  113. <view class="d-flex flex-row justify-between flex-wrap">
  114. <view
  115. v-for="(tab, k) in recommendLoader.content.value"
  116. :key="k"
  117. class="grid4-item position-relative mb-3"
  118. @click="handleGoDetails(tab)"
  119. >
  120. <text
  121. class="tag bg-mask-white color-primary radius-l p-1 position-absolute size-s text-lines-1"
  122. >
  123. {{ tab.title }}
  124. </text>
  125. <image
  126. class="w-100 height-250 radius-base"
  127. :src="tab.thumbnail || tab.image || AppCofig.defaultImage"
  128. :style="{
  129. backgroundImage: `url('${tab.thumbnail || tab.image}')`,
  130. backgroundSize: 'cover',
  131. }"
  132. mode="aspectFit"
  133. />
  134. </view>
  135. </view>
  136. </SimplePageContentLoader>
  137. </view>
  138. </view>
  139. <tabbar :current="0"></tabbar>
  140. </template>
  141. <script setup lang="ts">
  142. const MainBoxIcon1 = 'https://mncdn.wenlvti.net/app_static/minnan/images/home/MainBoxIcon10.png';
  143. const MainBoxIcon2 = 'https://mncdn.wenlvti.net/app_static/minnan/images/home/MainBoxIcon2.png';
  144. const MainBoxIcon3 = 'https://mncdn.wenlvti.net/app_static/minnan/images/home/MainBoxIcon3.png';
  145. const MainBoxIcon4 = 'https://mncdn.wenlvti.net/app_static/minnan/images/home/MainBoxIcon4.png';
  146. const MainBoxIcon5 = 'https://mncdn.wenlvti.net/app_static/minnan/images/home/MainBoxIcon5.png';
  147. const MainBoxIcon6 = 'https://mncdn.wenlvti.net/app_static/minnan/images/home/MainBoxIcon6.png';
  148. const MainBoxIcon7 = 'https://mncdn.wenlvti.net/app_static/minnan/images/home/MainBoxIcon9.png';
  149. const MainBoxIcon8 = 'https://mncdn.wenlvti.net/app_static/minnan/images/home/MainBoxIcon8.png';
  150. const ImageTest = 'https://mncdn.wenlvti.net/app_static/minnan/images/home/ImageTest.jpg';
  151. import { ref, watch } from 'vue';
  152. import { onShareTimeline, onShareAppMessage } from '@dcloudio/uni-app';
  153. import { navTo } from '@/components/utils/PageAction';
  154. import { useSimpleDataLoader } from '@/common/composeabe/SimpleDataLoader';
  155. import { useSimpleListAudioPlayer } from '@/common/composeabe/SimpleAudioPlayer';
  156. import CommonContent, { GetContentListParams } from '@/api/CommonContent';
  157. import UnmoveableContent from '@/api/inheritor/UnmoveableContent';
  158. import SeminarContent from '@/api/inheritor/SeminarContent';
  159. import ProjectsContent from '@/api/inheritor/ProjectsContent';
  160. import ProductsContent from '@/api/inheritor/ProductsContent';
  161. import AppCofig from '@/common/config/AppCofig';
  162. import VillageApi from '@/api/inhert/VillageApi';
  163. import ScenicSpotContent from '@/api/fusion/ScenicSpotContent';
  164. import IndexContent from '@/api/introduction/IndexContent';
  165. import StatsText from './parts/StatsText.vue';
  166. import HomeTitle from '@/pages/parts/HomeTitle.vue';
  167. import Tabbar from '@/common/components/tabs/tabbar.vue';
  168. import Box1AudioPlay from '@/pages/parts/Box1AudioPlay.vue';
  169. import SimplePageContentLoader from "@/common/components/SimplePageContentLoader.vue";
  170. const subTabs = [
  171. {
  172. name: '非遗项目',
  173. icon: MainBoxIcon6 ,
  174. onClick: () => navTo('/pages/inhert/intangible/list')
  175. },
  176. {
  177. name: '文物古迹',
  178. icon: MainBoxIcon5 ,
  179. onClick: () => navTo('/pages/inhert/artifact/list')
  180. },
  181. {
  182. name: '老字号',
  183. icon: MainBoxIcon7 ,
  184. onClick: () => navTo('/pages/inhert/old/list')
  185. },
  186. {
  187. name: '传统村落',
  188. icon: MainBoxIcon8 ,
  189. onClick: () => navTo('/pages/inhert/village/list')
  190. },
  191. {
  192. name: '闽南话',
  193. icon: MainBoxIcon1,
  194. onClick: () => navTo('/pages/inhert/language/list')
  195. },
  196. {
  197. name: '闽南美食',
  198. icon: MainBoxIcon2,
  199. onClick: () => navTo('/pages/introduction/food/list')
  200. },
  201. { name: '历史人物', icon: MainBoxIcon3, onClick: () => navTo('/pages/introduction/character/list') },
  202. {
  203. name: '闽南民俗',
  204. icon: MainBoxIcon4,
  205. onClick: () => navTo('/pages/introduction/custom/list')
  206. },
  207. ];
  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(313)
  261. , 1, 6)).list.sort(() => Math.random()>0.5?-1: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. list.push(...(await ProductsContent.getContentList(new GetContentListParams(), 1, 6)).list.map((p) => {
  286. p.itemType = p.type == GetContentListParams.TYPE_VIDEO ? 'video' : 'intangible';
  287. return p;
  288. }));
  289. return list;
  290. });
  291. const statsLoader = useSimpleDataLoader(async () => {
  292. const data = (await IndexContent.getStats());
  293. const semiCount = (await SeminarContent.getContentList(new GetContentListParams(), 1, 6)).total;
  294. const unmoveableCount = (await UnmoveableContent.getContentList(new GetContentListParams(), 1, 6)).total;
  295. return [
  296. {
  297. title: '非遗项目',
  298. type: '1',
  299. datas: data.ichData.filter((p: any) => [ '人类非遗', '国家级', '省级', '市级' ].includes(p.level_text)).map((item: any) => {
  300. return {
  301. title: item.level_text,
  302. value: item.total,
  303. onClick: () => navTo('/pages/inhert/intangible/list', { tab: 0, level: item.level }),
  304. }
  305. })
  306. },
  307. {
  308. title: '非遗传承人',
  309. type: '2',
  310. datas: data.inheritorData.filter((p: any) => [ '国家级', '省级', '市级' ].includes(p.title)).map((item: any) => {
  311. return {
  312. title: item.title,
  313. value: item.total,
  314. onClick: () => navTo('/pages/inhert/inheritor/list', { level: item.level }),
  315. }
  316. }).concat([
  317. {
  318. title: '',
  319. value: '',
  320. }
  321. ]),
  322. },
  323. {
  324. datas: [
  325. {
  326. title: '传习所',
  327. value: semiCount,
  328. onClick: () => navTo('/pages/inhert/map/index', { tab: 2 }),
  329. },
  330. {
  331. title: '传统村落',
  332. value: data.villageData[0].total,
  333. onClick: () => navTo('/pages/inhert/village/list'),
  334. },
  335. {
  336. title: '文物古迹',
  337. value: unmoveableCount,
  338. onClick: () => navTo('/pages/inhert/artifact/list'),
  339. },
  340. ],
  341. },
  342. {
  343. title: '不可移动文物',
  344. type: '3',
  345. datas: data.crData.map((item: any) => {
  346. return {
  347. title: item.title,
  348. value: item.total
  349. }
  350. })
  351. },
  352. {
  353. title: '闽南文化重要相关文物古迹',
  354. type: '2',
  355. datas: data.minnanCr.map((item: any) => {
  356. return {
  357. title: item.title,
  358. value: item.total
  359. }
  360. })
  361. },
  362. {
  363. title: '重要相关历史风貌区',
  364. type: '1',
  365. datas: data.historyData.map((item: any) => {
  366. return {
  367. title: item.title,
  368. value: item.total
  369. }
  370. })
  371. },
  372. {
  373. title: '传习中心',
  374. type: '3',
  375. datas: data.ichCenter.map((item: any) => {
  376. return {
  377. title: item.title,
  378. value: item.total
  379. }
  380. })
  381. },
  382. ]
  383. });
  384. function handleGoDetails(item: any) {
  385. switch (item.itemType) {
  386. case 'artifact':
  387. navTo('/pages/inhert/artifact/details', { id: item.id });
  388. break;
  389. case 'intangible':
  390. navTo('/pages/inhert/intangible/details', { id: item.id });
  391. break;
  392. case 'video':
  393. navTo('/pages/video/details', { id: item.id, modelId: item.modelId, mainBodyColumnId: item.mainBodyColumnId });
  394. break;
  395. default:
  396. navTo('/pages/article/details', { id: item.id, modelId: item.modelId, mainBodyColumnId: item.mainBodyColumnId });
  397. break;
  398. }
  399. }
  400. onShareTimeline(() => {
  401. return {};
  402. })
  403. onShareAppMessage(() => {
  404. return {};
  405. })
  406. </script>
  407. <style lang="scss">
  408. .page-home {
  409. .content {
  410. margin-top: 470rpx;
  411. }
  412. .map-tags {
  413. left: 0;
  414. top: 0;
  415. padding: 15rpx 0;
  416. font-size: 25rpx;
  417. .tag-bar {
  418. padding: 0 20rpx;
  419. view {
  420. display: flex;
  421. flex-direction: row;
  422. align-items: center;
  423. flex-shrink: 0;
  424. border-radius: 40rpx;
  425. padding: 10rpx 15rpx;
  426. background-color: #f7f3e8;
  427. color: #d9492e;
  428. margin-right: 10rpx;
  429. .iconfont {
  430. margin-right: 8rpx;
  431. }
  432. &.active {
  433. background-color: #d9492e;
  434. color: #f7f3e8;
  435. }
  436. }
  437. }
  438. }
  439. .grid4-item {
  440. width: 320rpx;
  441. .tag {
  442. top: 2rpx;
  443. right: 2rpx;
  444. }
  445. }
  446. .main-banner-box {
  447. position: relative;
  448. display: flex;
  449. flex-direction: column;
  450. overflow: hidden;
  451. border-radius: 15rpx;
  452. background: linear-gradient(180deg, #E5CDAB 0%, #F0E3D6 100%), #F7F3E8;
  453. padding: 20rpx;
  454. font-family: "SongtiSCBlack";
  455. color: #432A04;
  456. .title {
  457. font-size: 40rpx;
  458. }
  459. text {
  460. font-size: 35rpx;
  461. margin-top: 10rpx;
  462. }
  463. .more {
  464. margin-top: 30rpx;
  465. padding: 10rpx 20rpx;
  466. width: 150rpx;
  467. background-image: url('https://mncdn.wenlvti.net/app_static/minnan/images/home/MainBanner.png');
  468. background-size: 100% auto;
  469. background-repeat: no-repeat;
  470. text {
  471. font-family: initial;
  472. font-size: 30rpx;
  473. }
  474. }
  475. .footer {
  476. position: absolute;
  477. right: 0;
  478. bottom: 0;
  479. width: 370rpx;
  480. z-index: 2;
  481. height: auto;
  482. }
  483. }
  484. }
  485. </style>