index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. <script setup lang="ts">
  2. import itemGoods from '../../components/goodsItem/index.vue'
  3. import { StaticUrl } 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, opcity } = 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 currentIndex = ref([0, 1, 2, 3, 4])
  15. const navList = ref([
  16. { title: '为你推荐' },
  17. { title: '疯狂折扣' },
  18. { title: '' },
  19. { title: '地道特产' },
  20. { title: '预售' },
  21. ])
  22. const textArray = ref([
  23. '因订单高峰期,配送可能延迟,请提前下单',
  24. ])
  25. function handleChangeNav(idx: number) {
  26. navActive.value = idx
  27. }
  28. function handleScroll(e: UniHelper.ScrollViewOnScrollEvent) {
  29. const calculatedOpacity = e.detail.scrollTop / 100
  30. opcity.value = Math.min(1, Math.max(0.1, calculatedOpacity))
  31. }
  32. onMounted(() => {
  33. opcity.value = 0
  34. })
  35. function handleCommonClass(item: Api.xsbCategories) {
  36. console.log(item, '===================')
  37. if (!item.children) {
  38. useGlobalToast().show('敬请期待!')
  39. return
  40. }
  41. topNavActive.value = item.code
  42. leftActive.value = item.children && 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. function handleChangeSwiper(e: UniHelper.SwiperOnChangeEvent) {
  64. const current = e.detail.current
  65. const total = swiperClassList.value.length
  66. // 确保最多取到数组末尾,不足5个时从前面补
  67. const newIndices = []
  68. for (let i = 0; i < 5; i++) {
  69. let index = current + i
  70. if (index >= total) {
  71. // 如果超出范围,从0开始补足
  72. index = i
  73. }
  74. newIndices.push(index)
  75. }
  76. currentIndex.value = newIndices
  77. }
  78. </script>
  79. <template>
  80. <view class="page-xsb">
  81. <wd-navbar
  82. title=""
  83. :custom-style="`background-color: ${hexToRgba(useManualThemeStore().themeVars.colorTheme as string, opcity)};`"
  84. :bordered="false" :z-index="99" safe-area-inset-top left-arrow fixed @click-left="router.back()"
  85. >
  86. <template #left>
  87. <view class="h-full flex items-center">
  88. <wd-icon name="arrow-left" size="22px" color="#fff" />
  89. <view class="ml10rpx flex items-center" @click.stop="router.push({ name: 'xsb-selectAddress' })">
  90. <image :src="`${StaticUrl}/location.png`" class="h33.8rpx w29rpx" />
  91. <view class="ml10rpx max-w-280rpx truncate text-32rpx text-white">
  92. {{ SelectShopInfo?.shopName || '请选择位置' }}
  93. </view>
  94. </view>
  95. </view>
  96. </template>
  97. </wd-navbar>
  98. <scroll-view
  99. :lower-threshold="80"
  100. scroll-y enable-passive scroll-anchoring :scroll-top="scrollTop" class="ios content" @scroll="handleScroll" @scrolltolower="emit('scrollBottom')"
  101. >
  102. <view
  103. class="header-linear h320rpx px24rpx"
  104. :style="{ paddingTop: `${(Number(statusBarHeight) || 44) + MenuButtonHeight + 12}px` }"
  105. >
  106. <wd-skeleton animation="gradient" theme="image" :loading="loading" :row-col="[{ height: '30px', width: '100%' }]">
  107. <view class="h60rpx w-full flex items-center justify-between rounded-40rpx bg-white pr6rpx" @click="router.push({ name: 'xsb-search' })">
  108. <view class="flex items-center pb14rpx pl24rpx pt16rpx">
  109. <wd-icon name="search" size="14" color="#ccc" />
  110. <view class="search ml12rpx h-full w-full overflow-hidden">
  111. <wd-notice-bar
  112. :text="hotText.map((it) => it.searchName)" custom-class="notice-bar" color="#ccc"
  113. background-color="#fff" direction="vertical"
  114. />
  115. </view>
  116. </view>
  117. <view
  118. class="h50rpx w96rpx flex items-center justify-center rounded-26rpx bg-[var(--them-color)] text-24rpx text-white font-semibold"
  119. >
  120. 搜索
  121. </view>
  122. </view>
  123. </wd-skeleton>
  124. <scroll-view v-if="recommendText.length" scroll-x class="mb20rpx mt20rpx h44rpx whitespace-nowrap">
  125. <view class="h-full flex items-center">
  126. <view
  127. v-for="item in recommendText"
  128. :key="item.id" class="mr32rpx h-full flex items-center justify-center rounded-22rpx bg-[rgba(255,255,255,.5)] px16rpx text-24rpx"
  129. @click="router.push({ name: 'xsb-search', params: { text: item.searchName } })"
  130. >
  131. {{ item.searchName }}
  132. </view>
  133. </view>
  134. </scroll-view>
  135. </view>
  136. <view class="px24rpx" :class="[recommendText.length ? '-mt180rpx' : '-mt240rpx']">
  137. <wd-skeleton theme="image" animation="gradient" :loading="loading" :row-col="[{ height: '138px', width: '100%' }]">
  138. <wd-swiper
  139. :list="swiperList" :height="138" :indicator="false" value-key="advertImg" @click="handleGo"
  140. />
  141. </wd-skeleton>
  142. <view class="mt20rpx">
  143. <wd-card title="" custom-class="card-zt">
  144. <view :class="[loading ? 'p24rpx' : '']">
  145. <wd-skeleton
  146. :loading="loading"
  147. theme="image" :row-col="[
  148. [
  149. { width: '48px', height: '48px' },
  150. { width: '48px', height: '48px' },
  151. { width: '48px', height: '48px' },
  152. { width: '48px', height: '48px' },
  153. { width: '48px', height: '48px' },
  154. ],
  155. [
  156. { width: '48px', height: '48px' },
  157. { width: '48px', height: '48px' },
  158. { width: '48px', height: '48px' },
  159. { width: '48px', height: '48px' },
  160. { width: '48px', height: '48px' },
  161. ],
  162. [
  163. { width: '48px', height: '48px' },
  164. { width: '48px', height: '48px' },
  165. { width: '48px', height: '48px' },
  166. { width: '48px', height: '48px' },
  167. { width: '48px', height: '48px' },
  168. ],
  169. ]"
  170. >
  171. <view class="px24rpx pt24rpx">
  172. <view class="grid grid-cols-5 gap-x-24rpx gap-y-24rpx">
  173. <view v-for="item, index in classfiylist" :key="index" class="relative">
  174. <view @click="handleCommonClass(item)">
  175. <image :src="item.icon" class="h100rpx w100rpx" />
  176. <view class="mt12rpx whitespace-nowrap text-nowrap text-24rpx text-#222">
  177. {{ item.name }}
  178. </view>
  179. </view>
  180. <view v-if="!item.children" class="absolute left-0 top-0 h100rpx w100rpx flex items-center justify-center rounded-26rpx bg-[rgba(0,0,0,0.6)] text-16rpx text-white">
  181. 敬请期待
  182. </view>
  183. </view>
  184. </view>
  185. </view>
  186. <view v-if="swiperClassList.length" class="swiper-img swiper mt26rpx">
  187. <swiper class="h125rpx gap-16rpx" :display-multiple-items="5" @change="handleChangeSwiper">
  188. <swiper-item v-for="item, idx in swiperClassList" :key="item.id" class="mb20rpx flex flex-col items-center text-center" @click="handleSwiperClick({ index: idx, item })">
  189. <view class="pic-box">
  190. <image class="h72rpx w72rpx" :src="item.icon" />
  191. </view>
  192. <view class="text-24rpx text-#222">
  193. {{ item.name }}
  194. </view>
  195. <view v-if="!item.children" class="absolute left-50% top-0 h72rpx w72rpx flex items-center justify-center rounded-26rpx bg-[rgba(0,0,0,0.6)] text-16rpx text-white -translate-x-50%">
  196. 敬请期待
  197. </view>
  198. </swiper-item>
  199. </swiper>
  200. <view class="mt24rpx flex items-center justify-center">
  201. <view v-for="item, idx in swiperClassList" :key="idx" class="mr14rpx transition-all transition-duration-400 ease-in" :class="[currentIndex.includes(idx) ? 'rounded-12rpx w-40rpx h12rpx bg-[var(--them-color)]' : 'w12rpx h12rpx rounded-50% bg-#F0F0F0']" />
  202. </view>
  203. </view>
  204. </wd-skeleton>
  205. </view>
  206. </wd-card>
  207. </view>
  208. <view class="mt20rpx">
  209. <wd-notice-bar direction="vertical" :text="textArray" :delay="3" color="#222222" background-color="#fff">
  210. <template #prefix>
  211. <view class="mr20rpx">
  212. <wd-icon name="sound" size="22px" color="var(--them-color)" />
  213. </view>
  214. </template>
  215. </wd-notice-bar>
  216. </view>
  217. <view class="relative mt20rpx box-border" @click="useGlobalToast().show('敬请期待 !')">
  218. <image :src="`${StaticUrl}/xsb-index-bg.jpg`" class="h236rpx w-full rounded-16rpx" />
  219. <!-- <view class="absolute left-0 top-0 box-border h-full w-full flex items-end justify-between px16rpx pb16rpx">
  220. <image
  221. :src="`${StaticUrl}/xsb-index1.png`"
  222. class="h148rpx w328rpx"
  223. />
  224. <image
  225. :src="`${StaticUrl}/xsb-index2.png`"
  226. class="h148rpx w328rpx"
  227. />
  228. </view> -->
  229. </view>
  230. <view class="my20rpx">
  231. <scroll-view scroll-x class="whitespace-nowrap">
  232. <view class="h40rpx flex items-center">
  233. <view v-for="item, idx in navList" :key="idx" class="relative mr44rpx" @click="handleChangeNav(idx)">
  234. <image v-if="idx == 2" :src="`${StaticUrl}/chaozhi.png`" class="relative z-2 h-29.06rpx w-105.34rpx" />
  235. <view
  236. v-show="idx != 2" class="relative z-2 text-32rpx"
  237. :class="[navActive == idx ? 'text-36rpx font-semibold' : '']"
  238. >
  239. {{ item.title }}
  240. </view>
  241. <view
  242. v-show="navActive == idx"
  243. class="nav-line absolute bottom-0rpx left-50% z-1 h18rpx w80rpx rounded-10rpx -translate-x-50%"
  244. />
  245. </view>
  246. </view>
  247. </scroll-view>
  248. </view>
  249. <view class="mt20rpx">
  250. <wd-skeleton theme="image" animation="gradient" :loading="loading" :row-col="[[{ height: '568rpx', width: '344rpx' }, { height: '568rpx', width: '344rpx' }], [{ height: '568rpx', width: '344rpx' }, { height: '568rpx', width: '344rpx' }]]">
  251. <view class="flex items-center">
  252. <view class="w-full columns-2 gap-[10px]">
  253. <view class="mb-[10px] break-inside-avoid">
  254. <wd-swiper
  255. :autoplay="false" :list="[
  256. `${StaticUrl}/xsb-swiper1.png`,
  257. `${StaticUrl}/xsb-swiper2.png`,
  258. ]" :height="231"
  259. :indicator="{ type: 'dots-bar' }"
  260. @click="useGlobalToast().show('敬请期待 !')"
  261. />
  262. </view>
  263. <view v-for="it in goodsList" :key="it.id" class="mb-[10px] break-inside-avoid">
  264. <itemGoods :item-goods="it" />
  265. </view>
  266. </view>
  267. </view>
  268. </wd-skeleton>
  269. </view>
  270. <wd-loadmore :state="state" :loading-props="{ color: '#9ED605', size: 20 }" @reload="emit('scrollBottom')" />
  271. </view>
  272. <view class="h60rpx" />
  273. </scroll-view>
  274. </view>
  275. </template>
  276. <style scoped lang="scss">
  277. .content {
  278. height: calc(100vh - var(--window-top) - 100rpx);
  279. }
  280. .nav-line{
  281. 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%);
  282. }
  283. </style>