index.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <template>
  2. <div class="">
  3. <!-- <Navbar :title="`${menuName ?? ''}精品旅游`" /> -->
  4. <div v-if="filterList.length" class="sticky top-60 z-50 bg-white w-full border-t">
  5. <van-dropdown-menu active-color="#FF9300" ref="dropDownMenuRef">
  6. <van-dropdown-item @closed="onAreaFilterClose" :title="areaFilterTitle" ref="itemRef">
  7. <van-tree-select @click-nav="handleAreaClick" @click-item="handleFilterClick" v-model:active-id="activeId"
  8. v-model:main-active-index="areaIndex" :items="filterList" />
  9. </van-dropdown-item>
  10. <van-dropdown-item :title="writeTypeText" v-model="travelWriteType"
  11. :options="writeTypeList"></van-dropdown-item>
  12. </van-dropdown-menu>
  13. </div>
  14. <div class="px-10 pt-20">
  15. <van-list v-if="dataList.length" v-model:loading="loading" :immediate-check="false" :finished="finished"
  16. finished-text="" @load="loadMore">
  17. <template v-for="itemData in dataList">
  18. <NuxtLink class="group flex relative cursor-pointer bg-white pb-10 mb-20" :to="`/yj/${itemData.id}`">
  19. <div class="aspect-[120/80] h-80 shrink-0 rounded overflow-hidden bg-[#ddd]">
  20. <img :src="itemData.tourismUrl" class="w-full h-full rounded object-cover" alt="" srcset="" />
  21. </div>
  22. <div class="h-80 pl-[5px] flex flex-col text-[#FD9A00] justify-between w-[calc(100%-120px)]">
  23. <div class="truncate w-full text-[14px] ">
  24. <img v-if="itemData.isOriginal == 1" src="~/assets/img/yuanchuang.png" class="mt-3 w-[30px] h-[16px]" alt="" style="float:left;">
  25. {{ itemData.projectTitle }}
  26. </div>
  27. <div class="w-full overflow-x-auto scrollbar" v-if="itemData.noteLabel">
  28. <div class="flex flex-nowrap">
  29. <div v-for="tag in convertTag(itemData.noteLabel)" class="p-2 rounded-full border border-[#FD9A00] text-[10px] pr-12 pl-12 float-left mr-10 shrink-0">{{ tag }}</div>
  30. </div>
  31. </div>
  32. <div class="flex justify-end items-center text-[12px] text-[#999]">
  33. <div class="flex items-center mr-10">
  34. <van-icon name="eye-o" class="mr-5" />{{ transferCount(itemData.pageViewCount) }}
  35. </div>
  36. <div class="flex items-center mr-10">
  37. <van-icon name="good-job-o" class="mr-5" />{{ transferCount(itemData.likeCount) }}
  38. </div>
  39. </div>
  40. </div>
  41. <div class="w-full h-10 absolute top-[100%] left-0 flex items-center justify-between">
  42. <div v-for="item in 40" class="w-[2%] h-[1px] border border-[#ddd]"></div>
  43. </div>
  44. </NuxtLink>
  45. </template>
  46. </van-list>
  47. <Empty v-if="!dataList.length && !loading" />
  48. </div>
  49. </div>
  50. </template>
  51. <script setup>
  52. const AREA_TEXT = '地域'
  53. const filterList = ref([])//地域列表
  54. const curFilter = ref({})//当前筛选条件(国家)
  55. const areaIndex = ref(0)//地域索引
  56. const areaFilterTitle = ref(AREA_TEXT)
  57. const activeId = computed(() => curFilter.value.id)
  58. const activeIndex = ref('');
  59. const dropDownMenuRef = ref(null)
  60. // 获取筛选列表
  61. async function getFilters() {
  62. const { data } = await request(`website/tourism/projectTravelNotes/travelNotesDirectoryList`).finally(()=>{closeToast()})
  63. if (!Array.isArray(data)) return
  64. data.map((item, index) => {
  65. data[index].id = item.areaId
  66. data[index].text = item.areaName
  67. if (Array.isArray(item.children)) {
  68. item.children.map((item2, index2) => {
  69. data[index].children[index2].id = item2.countryId
  70. data[index].children[index2].text = item2.countryName
  71. data[index].children[index2].areaId = item.areaId
  72. })
  73. }
  74. })
  75. filterList.value = [{ id: 0, text: '全部', children: [{ id: 0, text: '全部' }] }, ...data]
  76. }
  77. // 监听地域筛选框收起
  78. function onAreaFilterClose() { areaIndex.value = activeIndex.value }
  79. const pageNum = ref(1)
  80. const pageSize = ref(10)
  81. const dataList = ref([])
  82. const loading = ref(false)
  83. const finished = ref(false)
  84. // 是否原创 0 全部 1 原创
  85. const travelWriteType = ref(0)
  86. const writeTypeList = ref([
  87. { text: '全部', value: 0 },
  88. { text: '原创', value: 1 },
  89. ])
  90. const writeTypeText = computed(() => writeTypeList.value[travelWriteType.value].value ? '原创' : '是否原创')
  91. watch(travelWriteType, () => {
  92. pageNum.value = 1
  93. dataList.value = []
  94. getList()
  95. })
  96. // 获取游记列表
  97. async function getList() {
  98. showLoadingToast({
  99. message: '加载中...',
  100. forbidClick: true,
  101. duration: 0,
  102. })
  103. const param = {
  104. pageNum: pageNum.value,
  105. pageSize: pageSize.value,
  106. }
  107. if (curFilter.value.id) {
  108. param.areaId = curFilter.value.areaId
  109. param.countryId = curFilter.value.id
  110. }
  111. if (travelWriteType.value) {
  112. param.travelWriteType = travelWriteType.value
  113. }
  114. loading.value = true
  115. const { data } = await request(`website/tourism/projectTravelNotes/travelNotesPageList`, { query: param }).finally(()=>closeToast())
  116. dataList.value = dataList.value.concat(data.dataList)
  117. loading.value = false
  118. if (dataList.value.length >= data.totalCount) {
  119. finished.value = true;
  120. } else {
  121. finished.value = false;
  122. }
  123. }
  124. // 选择洲
  125. function handleAreaClick(index) { areaIndex.value = index }
  126. // 选择国家
  127. function handleFilterClick(item) {
  128. curFilter.value = item
  129. if (!item.id) {
  130. areaFilterTitle.value = AREA_TEXT
  131. } else {
  132. const areaText = filterList.value[areaIndex.value].text || ''
  133. const cityText = item.text || ''
  134. activeIndex.value = areaIndex.value
  135. areaFilterTitle.value = areaText + '-' + cityText
  136. }
  137. pageNum.value = 1
  138. dataList.value = []
  139. getList()
  140. dropDownMenuRef.value && dropDownMenuRef.value.close()
  141. document.title=`${item.id?'游记-'+item.text:'旅游笔记'}`
  142. }
  143. function transferCount(num=0){
  144. if(isNaN(num)) return 0
  145. if(num>10000){
  146. return (num/10000).toFixed(1)+'w'
  147. }else{
  148. return num
  149. }
  150. }
  151. function loadMore() {
  152. pageNum.value++;
  153. getList()
  154. }
  155. function convertTag(str=''){
  156. if(typeof str!=='string') return []
  157. return str.split('&')
  158. }
  159. onMounted(() => {
  160. getList()
  161. getFilters()
  162. })
  163. useSeoMeta({
  164. title: `旅游笔记`,
  165. })
  166. </script>
  167. <style lang="scss" scoped>
  168. :root {
  169. --tree-select-item-active-color: red;
  170. /* 选中项背景颜色 */
  171. --tree-select-item-active-text-color: red;
  172. /* 选中项文本颜色 */
  173. --van-tree-select-item-active-color: red;
  174. }
  175. .scrollbar::-webkit-scrollbar {
  176. width: 0px;
  177. height: 0px;
  178. background-color: #ccc;
  179. }
  180. /* 滚动条滑块样式 */
  181. .scrollbar::-webkit-scrollbar-thumb {
  182. border-radius: 10px;
  183. -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
  184. background-color: #555;
  185. }
  186. </style>