index.vue 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. <script setup lang="ts">
  2. import itemGoods from '../../components/goodsItem/index.vue'
  3. import { StaticUrl, VITE_OSS_BASE_URL } from '@/config'
  4. import router from '@/router'
  5. const props = defineProps<{ error: any, lastPage: boolean, categoryList: Api.xsbCategories[], swiper: Api.xsbAdvertInfo[], hotText: Api.xsbSearchTerm[], recommendText: Api.xsbSearchTerm[], loading: boolean, goodsList: Api.xsbCategoryProductList[] }>()
  6. const emit = defineEmits(['changeNav', 'scrollBottom'])
  7. const { statusBarHeight, MenuButtonHeight } = storeToRefs(useSysStore())
  8. const { topNavActive, leftActive, backTop, SelectShopInfo, ScrollDown } = storeToRefs(useSysXsbStore())
  9. const swiperList = computed(() => props.swiper)
  10. const navActive = ref(0)
  11. const classfiylist = computed(() => props.categoryList.slice(0, 10))
  12. const swiperClassList = computed(() => props.categoryList.slice(10, props.categoryList.length))
  13. const scrollTop = ref()
  14. const navList = ref([
  15. { title: '为你推荐' },
  16. { title: '疯狂折扣' },
  17. { title: '' },
  18. { title: '地道特产' },
  19. { title: '预售' },
  20. ])
  21. const textArray = ref([
  22. '这是一条消息提示信息',
  23. '这是第二条消息',
  24. '这是第三条消息',
  25. ])
  26. function handleChangeNav(idx: number) {
  27. navActive.value = idx
  28. }
  29. function handleScroll(e: UniHelper.ScrollViewOnScrollEvent) {
  30. if (e.detail.scrollTop >= 80) {
  31. ScrollDown.value = true
  32. }
  33. else {
  34. ScrollDown.value = false
  35. }
  36. }
  37. onMounted(() => {
  38. ScrollDown.value = false
  39. })
  40. function handleCommonClass(item: Api.xsbCategories) {
  41. topNavActive.value = item.code
  42. leftActive.value = item.children[0].code
  43. emit('changeNav')
  44. }
  45. function handleSwiperClick(e: { index: number, item: Api.xsbCategories }) {
  46. handleCommonClass(e.item)
  47. }
  48. function handleGo(e: { index: number, item: Api.xsbAdvertInfo }) {
  49. console.log(e, '跳转消息')
  50. }
  51. const state = computed(() => {
  52. return props.error ? 'error' : !props.lastPage ? 'loading' : 'finished'
  53. })
  54. watch(() => backTop.value, () => {
  55. if (backTop.value) {
  56. scrollTop.value = null
  57. nextTick(() => {
  58. scrollTop.value = 0
  59. })
  60. backTop.value = false
  61. }
  62. })
  63. </script>
  64. <template>
  65. <view class="page-xsb">
  66. <wd-navbar
  67. title=""
  68. :custom-style="`background-color:${ScrollDown ? 'var(--them-color)' : 'transparent !important'}`"
  69. :bordered="false" :z-index="99" safe-area-inset-top left-arrow fixed @click-left="router.back()"
  70. >
  71. <template #left>
  72. <view class="h-full flex items-center">
  73. <wd-icon name="arrow-left" size="22px" color="#fff" />
  74. <view class="ml10rpx flex items-center" @click.stop="router.push({ name: 'xsb-selectAddress' })">
  75. <image :src="`${StaticUrl}/location.png`" class="h33.8rpx w29rpx" />
  76. <view class="ml10rpx max-w-280rpx truncate text-32rpx text-white">
  77. {{ SelectShopInfo?.shopName || '请选择位置' }}
  78. </view>
  79. </view>
  80. </view>
  81. </template>
  82. </wd-navbar>
  83. <scroll-view
  84. :lower-threshold="80"
  85. scroll-y enable-passive scroll-anchoring :scroll-top="scrollTop" class="content ios" @scroll="handleScroll" @scrolltolower="emit('scrollBottom')"
  86. >
  87. <view
  88. class="header-linear h320rpx px24rpx"
  89. :style="{ paddingTop: `${(Number(statusBarHeight) || 44) + MenuButtonHeight + 12}px` }"
  90. >
  91. <wd-skeleton theme="image" :loading="loading" :row-col="[{ height: '30px', width: '100%' }]">
  92. <view class="h60rpx w-full flex items-center justify-between rounded-40rpx bg-white pr6rpx" @click="router.push({ name: 'xsb-search' })">
  93. <view class="flex items-center pb14rpx pl24rpx pt16rpx">
  94. <wd-icon name="search" size="14" color="#ccc" />
  95. <view class="search ml12rpx h-full w-full overflow-hidden">
  96. <wd-notice-bar
  97. :text="hotText.map((it) => it.searchName)" custom-class="notice-bar" color="#ccc"
  98. background-color="#fff" direction="vertical"
  99. />
  100. </view>
  101. </view>
  102. <view
  103. class="h50rpx w96rpx flex items-center justify-center rounded-26rpx bg-[var(--them-color)] text-24rpx text-white font-semibold"
  104. >
  105. 搜索
  106. </view>
  107. </view>
  108. </wd-skeleton>
  109. <scroll-view v-if="recommendText.length" scroll-x class="mb20rpx mt20rpx h44rpx whitespace-nowrap">
  110. <view class="h-full flex items-center">
  111. <view
  112. v-for="item in recommendText"
  113. :key="item.id" class="mr32rpx h-full flex items-center justify-center rounded-22rpx bg-[rgba(255,255,255,.5)] px16rpx text-24rpx"
  114. @click="router.push({ name: 'xsb-search', params: { text: item.searchName } })"
  115. >
  116. {{ item.searchName }}
  117. </view>
  118. </view>
  119. </scroll-view>
  120. </view>
  121. <view class="px24rpx" :class="[recommendText.length ? '-mt180rpx' : '-mt240rpx']">
  122. <wd-skeleton theme="image" :loading="loading" :row-col="[{ height: '138px', width: '100%' }]">
  123. <wd-swiper
  124. :autoplay="false" :list="swiperList" :height="138" :indicator="false" value-key="advertImg" @click="handleGo"
  125. />
  126. </wd-skeleton>
  127. <view class="mt20rpx">
  128. <wd-card title="" custom-class="card-zt">
  129. <view :class="[loading ? 'p24rpx' : '']">
  130. <wd-skeleton
  131. :loading="loading"
  132. theme="image" :row-col="[
  133. [
  134. { width: '48px', height: '48px' },
  135. { width: '48px', height: '48px' },
  136. { width: '48px', height: '48px' },
  137. { width: '48px', height: '48px' },
  138. { width: '48px', height: '48px' },
  139. ],
  140. [
  141. { width: '48px', height: '48px' },
  142. { width: '48px', height: '48px' },
  143. { width: '48px', height: '48px' },
  144. { width: '48px', height: '48px' },
  145. { width: '48px', height: '48px' },
  146. ],
  147. [
  148. { width: '48px', height: '48px' },
  149. { width: '48px', height: '48px' },
  150. { width: '48px', height: '48px' },
  151. { width: '48px', height: '48px' },
  152. { width: '48px', height: '48px' },
  153. ],
  154. ]"
  155. >
  156. <view class="px24rpx pt24rpx">
  157. <view class="grid grid-cols-5 gap-x-38rpx gap-y-24rpx">
  158. <view v-for="item, index in classfiylist" :key="index" @click="handleCommonClass(item)">
  159. <image :src="item.icon" class="h100rpx w100rpx" />
  160. <view class="mt12rpx text-24rpx text-#222">
  161. {{ item.name }}
  162. </view>
  163. </view>
  164. </view>
  165. </view>
  166. <view class="swiper-img swiper pb20rpx">
  167. <wd-swiper
  168. :list="swiperClassList" :indicator="{ type: 'dots-bar' }" height="80"
  169. :display-multiple-items="5" :autoplay="false" :loop="false"
  170. custom-indicator-class="custom-indicator-class" value-key="icon" text-key="name"
  171. image-mode="aspectFit"
  172. @click="handleSwiperClick"
  173. />
  174. </view>
  175. </wd-skeleton>
  176. </view>
  177. </wd-card>
  178. </view>
  179. <view class="mt20rpx">
  180. <wd-notice-bar direction="vertical" :text="textArray" :delay="3" color="#222222" background-color="#fff">
  181. <template #prefix>
  182. <view class="mr20rpx">
  183. <wd-icon name="sound" size="22px" color="var(--them-color)" />
  184. </view>
  185. </template>
  186. </wd-notice-bar>
  187. </view>
  188. <view class="mt20rpx">
  189. <image :src="`${VITE_OSS_BASE_URL}2025/12/6671332ceef64985858aa8b548027bd3.png`" class="h236rpx w-full" />
  190. </view>
  191. <view class="my20rpx">
  192. <scroll-view scroll-x class="whitespace-nowrap">
  193. <view class="h40rpx flex items-center">
  194. <view v-for="item, idx in navList" :key="idx" class="relative mr44rpx" @click="handleChangeNav(idx)">
  195. <image v-if="idx == 2" :src="`${StaticUrl}/chaozhi.png`" class="relative z-2 h-29.06rpx w-105.34rpx" />
  196. <text
  197. v-show="idx != 2" class="relative z-2 text-32rpx"
  198. :class="[navActive == idx ? 'text-36rpx font-semibold' : '']"
  199. >
  200. {{ item.title }}
  201. </text>
  202. <view
  203. v-show="navActive == idx"
  204. class="nav-line absolute bottom-0rpx left-50% z-1 h18rpx w80rpx rounded-10rpx -translate-x-50%"
  205. />
  206. </view>
  207. </view>
  208. </scroll-view>
  209. </view>
  210. <view class="mt20rpx">
  211. <view class="flex items-center">
  212. <scroll-view scroll-y type="custom">
  213. <grid-view type="masonry" cross-axis-count="2" main-axis-gap="10" cross-axis-gap="10">
  214. <wd-swiper
  215. :autoplay="false" :list="[
  216. `${StaticUrl}/xsb-swiper1.png`,
  217. ]" :height="231"
  218. />
  219. <view v-for="it in goodsList" :key="it.id">
  220. <itemGoods :item-goods="it" />
  221. </view>
  222. </grid-view>
  223. </scroll-view>
  224. </view>
  225. </view>
  226. <wd-loadmore :state="state" :loading-props="{ color: '#9ED605', size: 20 }" @reload="emit('scrollBottom')" />
  227. </view>
  228. <view class="h60rpx" />
  229. </scroll-view>
  230. </view>
  231. </template>
  232. <style scoped lang="scss">
  233. .content {
  234. height: calc(100vh - var(--window-top) - 100rpx);
  235. }
  236. .nav-line{
  237. background: linear-gradient( 90deg, #9ED605 0%, rgba(158,214,5,0.7) 43%, rgba(158,214,5,0.2) 79%, rgba(158,214,5,0) 100%);
  238. }
  239. </style>