mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-uniapp.git
synced 2026-11-13 04:18:53 +08:00
feat(uniapp): 新增首页组合组件 homeComb 并完善页面及楼层装修样式
This commit is contained in:
@@ -1,251 +1,262 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="home-page" :style="[themeStyle, pageBgStyle]">
|
<view class="home-page" :style="[themeStyle, pageBgStyle]">
|
||||||
<view
|
<view
|
||||||
v-for="(item, index) in pageData.list"
|
v-for="(item, index) in pageData.list"
|
||||||
:key="`${item.type}-${index}`"
|
:key="`${item.type}-${index}`"
|
||||||
class="floor-block"
|
class="floor-block"
|
||||||
>
|
>
|
||||||
<u-navbar
|
<u-navbar
|
||||||
class="navbar"
|
class="navbar"
|
||||||
v-if="item.type == 'search'"
|
v-if="item.type == 'search'"
|
||||||
:auto-back="false"
|
:auto-back="false"
|
||||||
:fixed="index === 1 ? false : true"
|
:fixed="index === 1 ? false : true"
|
||||||
:placeholder="index === 1 ? false : true"
|
:placeholder="index === 1 ? false : true"
|
||||||
left-icon=""
|
left-icon=""
|
||||||
title=""
|
title=""
|
||||||
bg-color="#ffffff"
|
:bg-color="topColor"
|
||||||
>
|
>
|
||||||
<template #left>
|
<template #left>
|
||||||
<view class="navbar-search-wrap" :style="searchBarStyle" @click.stop>
|
<view class="navbar-search-wrap" :style="searchBarStyle" @click.stop>
|
||||||
<search :res="item.options" />
|
<search :res="item.options" />
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
</u-navbar>
|
</u-navbar>
|
||||||
<carousel v-if="item.type == 'carousel'" :res="item.options" />
|
<homeComb v-if="item.type == 'homeComb'" :res="item.options" />
|
||||||
<titleLayout v-if="item.type == 'title'" :res="item.options" />
|
<carousel v-if="item.type == 'carousel'" :res="item.options" />
|
||||||
<leftOneRightTwo v-if="item.type == 'leftOneRightTwo'" :res="item.options" />
|
<titleLayout v-if="item.type == 'title'" :res="item.options" />
|
||||||
<leftTwoRightOne v-if="item.type == 'leftTwoRightOne'" :res="item.options" />
|
<leftOneRightTwo v-if="item.type == 'leftOneRightTwo'" :res="item.options" />
|
||||||
<topOneBottomTwo v-if="item.type == 'topOneBottomTwo'" :res="item.options" />
|
<leftTwoRightOne v-if="item.type == 'leftTwoRightOne'" :res="item.options" />
|
||||||
<topTwoBottomOne v-if="item.type == 'topTwoBottomOne'" :res="item.options" />
|
<topOneBottomTwo v-if="item.type == 'topOneBottomTwo'" :res="item.options" />
|
||||||
<flexThree v-if="item.type == 'flexThree'" :res="item.options" />
|
<topTwoBottomOne v-if="item.type == 'topTwoBottomOne'" :res="item.options" />
|
||||||
<flexFive v-if="item.type == 'flexFive'" :res="item.options" />
|
<flexThree v-if="item.type == 'flexThree'" :res="item.options" />
|
||||||
<flexFour v-if="item.type == 'flexFour'" :res="item.options" />
|
<flexFive v-if="item.type == 'flexFive'" :res="item.options" />
|
||||||
<flexTwo v-if="item.type == 'flexTwo'" :res="item.options" />
|
<flexFour v-if="item.type == 'flexFour'" :res="item.options" />
|
||||||
<textPicture v-if="item.type == 'textPicture'" :res="item.options" />
|
<flexTwo v-if="item.type == 'flexTwo'" :res="item.options" />
|
||||||
<menuLayout v-if="item.type == 'menu'" :res="item.options" />
|
<textPicture v-if="item.type == 'textPicture'" :res="item.options" />
|
||||||
<flexOne v-if="item.type == 'flexOne'" :res="item.options" />
|
<menuLayout v-if="item.type == 'menu'" :res="item.options" />
|
||||||
<goods
|
<flexOne v-if="item.type == 'flexOne'" :res="item.options" />
|
||||||
v-if="item.type == 'goods'"
|
<goods
|
||||||
:enableBottomLoad="enableLoad"
|
v-if="item.type == 'goods'"
|
||||||
:res="item.options"
|
:enableBottomLoad="enableLoad"
|
||||||
/>
|
:res="item.options"
|
||||||
<group v-if="item.type == 'group'" :res="item.options" />
|
/>
|
||||||
<notice v-if="item.type == 'notice'" :res="item.options" />
|
<group v-if="item.type == 'group'" :res="item.options" />
|
||||||
<promotions v-if="item.type == 'promotionDetail'" :res="item.options" />
|
<notice v-if="item.type == 'notice'" :res="item.options" />
|
||||||
<videoLayout v-if="item.type == 'video'" :res="item.options" />
|
<promotions v-if="item.type == 'promotionDetail'" :res="item.options" />
|
||||||
<blank v-if="item.type == 'blank'" :res="item.options" />
|
<videoLayout v-if="item.type == 'video'" :res="item.options" />
|
||||||
<lineLayout v-if="item.type == 'line'" :res="item.options" />
|
<blank v-if="item.type == 'blank'" :res="item.options" />
|
||||||
<richText v-if="item.type == 'richText'" :res="item.options" />
|
<lineLayout v-if="item.type == 'line'" :res="item.options" />
|
||||||
<integral v-if="item.type == 'integral'" :res="item.options" />
|
<richText v-if="item.type == 'richText'" :res="item.options" />
|
||||||
<coupon v-if="item.type == 'coupon'" :res="item.options" />
|
<integral v-if="item.type == 'integral'" :res="item.options" />
|
||||||
<articleList v-if="item.type == 'article'" :res="item.options" />
|
<coupon v-if="item.type == 'coupon'" :res="item.options" />
|
||||||
<shopList v-if="item.type == 'shop'" :res="item.options" />
|
<articleList v-if="item.type == 'article'" :res="item.options" />
|
||||||
</view>
|
<shopList v-if="item.type == 'shop'" :res="item.options" />
|
||||||
<fetchCoupon ref="couponRef" />
|
</view>
|
||||||
</view>
|
<fetchCoupon ref="couponRef" />
|
||||||
</template>
|
</view>
|
||||||
|
</template>
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, computed } from 'vue'
|
<script setup lang="ts">
|
||||||
import {
|
import { ref, computed } from 'vue'
|
||||||
onShow,
|
import {
|
||||||
onReady,
|
onShow,
|
||||||
onReachBottom,
|
onReady,
|
||||||
onPullDownRefresh,
|
onReachBottom,
|
||||||
} from '@dcloudio/uni-app'
|
onPullDownRefresh,
|
||||||
import { useStore } from '@/store'
|
} from '@dcloudio/uni-app'
|
||||||
import { getThemeStyle } from '@/utils/theme'
|
import { useStore } from '@/store'
|
||||||
import carousel from '@/pages/tabbar/home/template/tpl_banner.vue'
|
import { getThemeStyle } from '@/utils/theme'
|
||||||
import titleLayout from '@/pages/tabbar/home/template/tpl_title.vue'
|
import carousel from '@/pages/tabbar/home/template/tpl_banner.vue'
|
||||||
import leftOneRightTwo from '@/pages/tabbar/home/template/tpl_left_one_right_two.vue'
|
import titleLayout from '@/pages/tabbar/home/template/tpl_title.vue'
|
||||||
import leftTwoRightOne from '@/pages/tabbar/home/template/tpl_left_two_right_one.vue'
|
import leftOneRightTwo from '@/pages/tabbar/home/template/tpl_left_one_right_two.vue'
|
||||||
import topOneBottomTwo from '@/pages/tabbar/home/template/tpl_top_one_bottom_two.vue'
|
import leftTwoRightOne from '@/pages/tabbar/home/template/tpl_left_two_right_one.vue'
|
||||||
import topTwoBottomOne from '@/pages/tabbar/home/template/tpl_top_two_bottom_one.vue'
|
import topOneBottomTwo from '@/pages/tabbar/home/template/tpl_top_one_bottom_two.vue'
|
||||||
import flexOne from '@/pages/tabbar/home/template/tpl_flex_one.vue'
|
import topTwoBottomOne from '@/pages/tabbar/home/template/tpl_top_two_bottom_one.vue'
|
||||||
import flexTwo from '@/pages/tabbar/home/template/tpl_flex_two.vue'
|
import flexOne from '@/pages/tabbar/home/template/tpl_flex_one.vue'
|
||||||
import flexThree from '@/pages/tabbar/home/template/tpl_flex_three.vue'
|
import flexTwo from '@/pages/tabbar/home/template/tpl_flex_two.vue'
|
||||||
import flexFive from '@/pages/tabbar/home/template/tpl_flex_five.vue'
|
import flexThree from '@/pages/tabbar/home/template/tpl_flex_three.vue'
|
||||||
import flexFour from '@/pages/tabbar/home/template/tpl_flex_four.vue'
|
import flexFive from '@/pages/tabbar/home/template/tpl_flex_five.vue'
|
||||||
import textPicture from '@/pages/tabbar/home/template/tpl_text_picture.vue'
|
import flexFour from '@/pages/tabbar/home/template/tpl_flex_four.vue'
|
||||||
import menuLayout from '@/pages/tabbar/home/template/tpl_menu.vue'
|
import textPicture from '@/pages/tabbar/home/template/tpl_text_picture.vue'
|
||||||
import search from '@/pages/tabbar/home/template/tpl_search.vue'
|
import menuLayout from '@/pages/tabbar/home/template/tpl_menu.vue'
|
||||||
import group from '@/pages/tabbar/home/template/tpl_group.vue'
|
import search from '@/pages/tabbar/home/template/tpl_search.vue'
|
||||||
import videoLayout from '@/pages/tabbar/home/template/tpl_video.vue'
|
import group from '@/pages/tabbar/home/template/tpl_group.vue'
|
||||||
import goods from '@/pages/tabbar/home/template/tpl_goods.vue'
|
import videoLayout from '@/pages/tabbar/home/template/tpl_video.vue'
|
||||||
import notice from '@/pages/tabbar/home/template/tpl_notice.vue'
|
import goods from '@/pages/tabbar/home/template/tpl_goods.vue'
|
||||||
import promotions from '@/pages/tabbar/home/template/tpl_promotions_detail.vue'
|
import notice from '@/pages/tabbar/home/template/tpl_notice.vue'
|
||||||
import fetchCoupon from '@/pages/tabbar/home/template/fetch_coupon.vue'
|
import promotions from '@/pages/tabbar/home/template/tpl_promotions_detail.vue'
|
||||||
import blank from '@/pages/tabbar/home/template/tpl_blank.vue'
|
import fetchCoupon from '@/pages/tabbar/home/template/fetch_coupon.vue'
|
||||||
import lineLayout from '@/pages/tabbar/home/template/tpl_line.vue'
|
import blank from '@/pages/tabbar/home/template/tpl_blank.vue'
|
||||||
import richText from '@/pages/tabbar/home/template/tpl_rich_text.vue'
|
import lineLayout from '@/pages/tabbar/home/template/tpl_line.vue'
|
||||||
import integral from '@/pages/tabbar/home/template/tpl_integral.vue'
|
import richText from '@/pages/tabbar/home/template/tpl_rich_text.vue'
|
||||||
import coupon from '@/pages/tabbar/home/template/tpl_coupon.vue'
|
import integral from '@/pages/tabbar/home/template/tpl_integral.vue'
|
||||||
import articleList from '@/pages/tabbar/home/template/tpl_article.vue'
|
import coupon from '@/pages/tabbar/home/template/tpl_coupon.vue'
|
||||||
import shopList from '@/pages/tabbar/home/template/tpl_shop.vue'
|
import articleList from '@/pages/tabbar/home/template/tpl_article.vue'
|
||||||
import { getFloorData } from '@/api/home'
|
import shopList from '@/pages/tabbar/home/template/tpl_shop.vue'
|
||||||
|
import homeComb from '@/pages/tabbar/home/template/tpl_home_comb.vue'
|
||||||
const HOME_LAYOUT_PADDING_RPX = 16
|
import { getFloorData } from '@/api/home'
|
||||||
|
|
||||||
const store = useStore()
|
const HOME_LAYOUT_PADDING_RPX = 16
|
||||||
const themeStyle = computed(() => getThemeStyle(store.state.theme))
|
|
||||||
|
const store = useStore()
|
||||||
const couponRef = ref<InstanceType<typeof fetchCoupon>>()
|
const themeStyle = computed(() => getThemeStyle(store.state.theme))
|
||||||
const pageData = ref<{ list: any[] }>({ list: [] })
|
|
||||||
const enableLoad = ref(false)
|
const couponRef = ref<InstanceType<typeof fetchCoupon>>()
|
||||||
const loading = ref(false)
|
const pageData = ref<Record<string, any>>({ list: [] })
|
||||||
const searchBarWidth = ref(0)
|
const enableLoad = ref(false)
|
||||||
|
const loading = ref(false)
|
||||||
// 页面设置-样式:画布背景(背景色 / 背景图 + 填充方式)
|
const searchBarWidth = ref(0)
|
||||||
const pageBgStyle = computed(() => {
|
|
||||||
const data: any = pageData.value
|
const topColor = computed(() => pageData.value?.topColor || '#ffffff')
|
||||||
if (data?.bgType === 'image' && data?.bgImage) {
|
|
||||||
const size =
|
// 页面设置-样式:画布背景(背景色 / 背景图 + 填充方式)
|
||||||
data.bgFill === 'contain'
|
const pageBgStyle = computed(() => {
|
||||||
? 'contain'
|
const data: any = pageData.value
|
||||||
: data.bgFill === 'cover'
|
if (data?.bgType === 'image' && data?.bgImage) {
|
||||||
? 'cover'
|
const size =
|
||||||
: '100% 100%'
|
data.bgFill === 'contain'
|
||||||
return {
|
? 'contain'
|
||||||
backgroundImage: `url(${data.bgImage})`,
|
: data.bgFill === 'cover'
|
||||||
backgroundSize: size,
|
? 'cover'
|
||||||
backgroundRepeat: 'no-repeat',
|
: '100% 100%'
|
||||||
backgroundColor: data.bgColor || '#f9f9f9',
|
return {
|
||||||
}
|
backgroundImage: `url(${data.bgImage})`,
|
||||||
}
|
backgroundSize: size,
|
||||||
if (data?.bgColor) {
|
backgroundRepeat: 'no-repeat',
|
||||||
return { backgroundColor: data.bgColor }
|
backgroundColor: data.bgColor || '#f9f9f9',
|
||||||
}
|
}
|
||||||
return {}
|
}
|
||||||
})
|
if (data?.bgColor) {
|
||||||
|
return { backgroundColor: data.bgColor }
|
||||||
const searchBarStyle = computed(() => {
|
}
|
||||||
if (searchBarWidth.value) {
|
return {}
|
||||||
return { width: `${searchBarWidth.value}px` }
|
})
|
||||||
}
|
|
||||||
return { width: '100%' }
|
const searchBarStyle = computed(() => {
|
||||||
})
|
if (searchBarWidth.value) {
|
||||||
|
return { width: `${searchBarWidth.value}px` }
|
||||||
function setCapsuleInset() {
|
}
|
||||||
try {
|
return { width: '100%' }
|
||||||
const { windowWidth } = uni.getWindowInfo()
|
})
|
||||||
const leftPadding = uni.upx2px(HOME_LAYOUT_PADDING_RPX)
|
|
||||||
const rightPadding = uni.upx2px(HOME_LAYOUT_PADDING_RPX)
|
function setCapsuleInset() {
|
||||||
// #ifdef MP-WEIXIN
|
try {
|
||||||
const menuButton = uni.getMenuButtonBoundingClientRect()
|
const { windowWidth } = uni.getWindowInfo()
|
||||||
searchBarWidth.value = windowWidth - (windowWidth - menuButton.left) - leftPadding
|
const leftPadding = uni.upx2px(HOME_LAYOUT_PADDING_RPX)
|
||||||
// #endif
|
const rightPadding = uni.upx2px(HOME_LAYOUT_PADDING_RPX)
|
||||||
// #ifndef MP-WEIXIN
|
// #ifdef MP-WEIXIN
|
||||||
searchBarWidth.value = windowWidth - leftPadding - rightPadding
|
const menuButton = uni.getMenuButtonBoundingClientRect()
|
||||||
// #endif
|
searchBarWidth.value = windowWidth - (windowWidth - menuButton.left) - leftPadding
|
||||||
} catch (e) {
|
// #endif
|
||||||
searchBarWidth.value = 0
|
// #ifndef MP-WEIXIN
|
||||||
}
|
searchBarWidth.value = windowWidth - leftPadding - rightPadding
|
||||||
}
|
// #endif
|
||||||
|
} catch (e) {
|
||||||
function fetchCouponFn() {
|
searchBarWidth.value = 0
|
||||||
couponRef.value?.firstGetAuto()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function fetchCouponFn() {
|
||||||
if (loading.value) return
|
couponRef.value?.firstGetAuto()
|
||||||
loading.value = true
|
}
|
||||||
getFloorData()
|
|
||||||
.then((res) => {
|
function init() {
|
||||||
const payload = res?.data != null ? res.data : res
|
if (loading.value) return
|
||||||
const pageDataStr = payload?.result?.pageData
|
loading.value = true
|
||||||
const isSuccess = payload?.success === true || payload?.code === 200
|
getFloorData()
|
||||||
if (!isSuccess || !pageDataStr) return
|
.then((res) => {
|
||||||
|
const payload = res?.data != null ? res.data : res
|
||||||
try {
|
const pageDataStr = payload?.result?.pageData
|
||||||
const result = JSON.parse(pageDataStr)
|
const isSuccess = payload?.success === true || payload?.code === 200
|
||||||
pageData.value = Array.isArray(result?.list)
|
if (!isSuccess || !pageDataStr) return
|
||||||
? { ...result, list: result.list.filter((i: any) => !i?.hidden) }
|
|
||||||
: { list: [] }
|
try {
|
||||||
// 页面设置-内容:页面标题同步到导航栏
|
const result = JSON.parse(pageDataStr)
|
||||||
if (result?.title) {
|
pageData.value = Array.isArray(result?.list)
|
||||||
uni.setNavigationBarTitle({ title: result.title })
|
? { ...result, list: result.list.filter((i: any) => !i?.hidden) }
|
||||||
}
|
: { list: [] }
|
||||||
const lastItem = pageData.value.list[pageData.value.list.length - 1]
|
// 页面设置-内容:页面标题同步到导航栏
|
||||||
enableLoad.value =
|
if (result?.title) {
|
||||||
lastItem?.type === 'goods' || lastItem?.model === 'goods'
|
uni.setNavigationBarTitle({ title: result.title })
|
||||||
} catch (parseError) {
|
}
|
||||||
console.error('parse pageData failed', parseError)
|
// 页面设置-样式:顶部颜色与标题颜色同步到导航栏
|
||||||
}
|
if (result?.topColor || result?.titleColor) {
|
||||||
})
|
uni.setNavigationBarColor({
|
||||||
.catch((err) => {
|
frontColor: result?.titleColor === 'white' ? '#ffffff' : '#000000',
|
||||||
console.error('getFloorData failed', err)
|
backgroundColor: result?.topColor || '#ffffff',
|
||||||
})
|
})
|
||||||
.finally(() => {
|
}
|
||||||
loading.value = false
|
const lastItem = pageData.value.list[pageData.value.list.length - 1]
|
||||||
})
|
enableLoad.value =
|
||||||
}
|
lastItem?.type === 'goods' || lastItem?.model === 'goods'
|
||||||
|
} catch (parseError) {
|
||||||
onReady(() => {
|
console.error('parse pageData failed', parseError)
|
||||||
setCapsuleInset()
|
}
|
||||||
init()
|
})
|
||||||
// #ifdef MP-WEIXIN
|
.catch((err) => {
|
||||||
uni.showShareMenu({ withShareTicket: true })
|
console.error('getFloorData failed', err)
|
||||||
// #endif
|
})
|
||||||
})
|
.finally(() => {
|
||||||
|
loading.value = false
|
||||||
onShow(() => {
|
})
|
||||||
setTimeout(() => {
|
}
|
||||||
fetchCouponFn()
|
|
||||||
}, 1000)
|
onReady(() => {
|
||||||
})
|
setCapsuleInset()
|
||||||
|
init()
|
||||||
onReachBottom(() => {
|
// #ifdef MP-WEIXIN
|
||||||
uni.$emit('onReachBottom', true)
|
uni.showShareMenu({ withShareTicket: true })
|
||||||
})
|
// #endif
|
||||||
|
})
|
||||||
onPullDownRefresh(() => {
|
|
||||||
init()
|
onShow(() => {
|
||||||
uni.stopPullDownRefresh()
|
setTimeout(() => {
|
||||||
})
|
fetchCouponFn()
|
||||||
</script>
|
}, 1000)
|
||||||
|
})
|
||||||
<style scoped lang="scss">
|
|
||||||
@import '@/pages/tabbar/home/template/tpl.scss';
|
onReachBottom(() => {
|
||||||
|
uni.$emit('onReachBottom', true)
|
||||||
.home-page {
|
})
|
||||||
width: 100%;
|
|
||||||
min-height: 100%;
|
onPullDownRefresh(() => {
|
||||||
background: #f9f9f9;
|
init()
|
||||||
}
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
.floor-block {
|
</script>
|
||||||
width: 100%;
|
|
||||||
display: block;
|
<style scoped lang="scss">
|
||||||
}
|
@import '@/pages/tabbar/home/template/tpl.scss';
|
||||||
|
|
||||||
.navbar {
|
.home-page {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
min-height: 100%;
|
||||||
:deep(.u-navbar__content) {
|
background: #f9f9f9;
|
||||||
width: 100%;
|
}
|
||||||
}
|
|
||||||
|
.floor-block {
|
||||||
:deep(.u-navbar__content__left) {
|
width: 100%;
|
||||||
flex: 1;
|
display: block;
|
||||||
width: auto !important;
|
}
|
||||||
max-width: 100%;
|
|
||||||
padding: 0 0 0 $home-layout-padding !important;
|
.navbar {
|
||||||
}
|
width: 100%;
|
||||||
}
|
|
||||||
|
:deep(.u-navbar__content) {
|
||||||
.navbar-search-wrap {
|
width: 100%;
|
||||||
box-sizing: border-box;
|
}
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
:deep(.u-navbar__content__left) {
|
||||||
}
|
flex: 1;
|
||||||
</style>
|
width: auto !important;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 0 0 0 $home-layout-padding !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-search-wrap {
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -43,6 +43,7 @@
|
|||||||
class="cp1-item"
|
class="cp1-item"
|
||||||
v-for="item in couponList"
|
v-for="item in couponList"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
|
:style="itemGapStyle"
|
||||||
@click="receive(item)"
|
@click="receive(item)"
|
||||||
>
|
>
|
||||||
<view class="cp1-left">
|
<view class="cp1-left">
|
||||||
@@ -77,6 +78,7 @@
|
|||||||
class="cp2-item"
|
class="cp2-item"
|
||||||
v-for="item in couponList"
|
v-for="item in couponList"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
|
:style="itemGapStyle"
|
||||||
@click="receive(item)"
|
@click="receive(item)"
|
||||||
>
|
>
|
||||||
<view class="cp2-top">
|
<view class="cp2-top">
|
||||||
@@ -107,6 +109,7 @@
|
|||||||
class="cp3-item"
|
class="cp3-item"
|
||||||
v-for="item in couponList"
|
v-for="item in couponList"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
|
:style="itemGapStyle"
|
||||||
@click="receive(item)"
|
@click="receive(item)"
|
||||||
>
|
>
|
||||||
<view class="cp3-left">
|
<view class="cp3-left">
|
||||||
@@ -136,6 +139,7 @@
|
|||||||
class="cp4-item"
|
class="cp4-item"
|
||||||
v-for="item in couponList"
|
v-for="item in couponList"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
|
:style="itemGapStyle"
|
||||||
@click="receive(item)"
|
@click="receive(item)"
|
||||||
>
|
>
|
||||||
<view class="cp4-left">
|
<view class="cp4-left">
|
||||||
@@ -177,6 +181,11 @@ const layoutStyle = computed(() => (props.res && props.res.layoutStyle) || "1");
|
|||||||
|
|
||||||
// 面板保存过样式字段才启用自定义样式,老数据保持原样
|
// 面板保存过样式字段才启用自定义样式,老数据保持原样
|
||||||
const styled = computed(() => props.res && props.res.paddingTop !== undefined);
|
const styled = computed(() => props.res && props.res.paddingTop !== undefined);
|
||||||
|
const itemGapStyle = computed(() => {
|
||||||
|
if (!styled.value) return {};
|
||||||
|
const gap = props.res?.contentGap !== undefined ? Number(props.res.contentGap) || 0 : 5;
|
||||||
|
return { marginRight: `${gap}rpx` };
|
||||||
|
});
|
||||||
const wrapperStyle = computed(() => {
|
const wrapperStyle = computed(() => {
|
||||||
const res = props.res || {};
|
const res = props.res || {};
|
||||||
if (styled.value) {
|
if (styled.value) {
|
||||||
@@ -291,6 +300,12 @@ function receive(item: any) {
|
|||||||
.cp-scroll {
|
.cp-scroll {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
.cp1-item:last-child,
|
||||||
|
.cp2-item:last-child,
|
||||||
|
.cp3-item:last-child,
|
||||||
|
.cp4-item:last-child {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
.cp-notch {
|
.cp-notch {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 60rpx;
|
right: 60rpx;
|
||||||
|
|||||||
@@ -26,13 +26,22 @@ const hasHotZone = computed(() => {
|
|||||||
return Array.isArray(zoneInfo) ? zoneInfo.length > 0 : !!zoneInfo;
|
return Array.isArray(zoneInfo) ? zoneInfo.length > 0 : !!zoneInfo;
|
||||||
});
|
});
|
||||||
|
|
||||||
const wrapperStyle = computed(() => ({
|
const wrapperStyle = computed(() => {
|
||||||
background: props.res?.bgColor ?? "transparent",
|
const r = props.res || {};
|
||||||
padding: `${props.res?.paddingTop ?? 0}rpx ${props.res?.paddingX ?? 0}rpx ${props.res?.paddingBottom ?? 0}rpx`,
|
const bg =
|
||||||
marginBottom: `${props.res?.pageGap ?? 0}rpx`,
|
r.bgColor1 !== undefined
|
||||||
borderRadius: `${props.res?.borderRadius ?? 0}rpx`,
|
? !r.bgColor2 || r.bgColor1 === r.bgColor2
|
||||||
overflow: (props.res?.borderRadius ?? 0) > 0 ? "hidden" : "visible",
|
? r.bgColor1
|
||||||
}));
|
: `linear-gradient(180deg, ${r.bgColor1}, ${r.bgColor2})`
|
||||||
|
: r.bgColor ?? "transparent";
|
||||||
|
return {
|
||||||
|
background: bg,
|
||||||
|
padding: `${r.paddingTop ?? 0}rpx ${r.paddingX ?? 0}rpx ${r.paddingBottom ?? 0}rpx`,
|
||||||
|
marginBottom: `${r.pageGap ?? 0}rpx`,
|
||||||
|
borderRadius: `${r.borderRadius ?? 0}rpx`,
|
||||||
|
overflow: (r.borderRadius ?? 0) > 0 ? "hidden" : "visible",
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const contentStyle = computed(() => ({
|
const contentStyle = computed(() => ({
|
||||||
borderRadius: `${props.res?.imgRadius ?? 0}rpx`,
|
borderRadius: `${props.res?.imgRadius ?? 0}rpx`,
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ const nameStyle = computed(() =>
|
|||||||
const salesStyle = computed(() =>
|
const salesStyle = computed(() =>
|
||||||
props.res?.salesColor ? { color: props.res.salesColor } : {}
|
props.res?.salesColor ? { color: props.res.salesColor } : {}
|
||||||
);
|
);
|
||||||
const rpx = (v: any) => `${(Number(v) || 0) * 2}rpx`;
|
const rpx = (v: any) => `${Number(v) || 0}rpx`;
|
||||||
const wrapperStyle = computed(() => {
|
const wrapperStyle = computed(() => {
|
||||||
const res = props.res || {};
|
const res = props.res || {};
|
||||||
const bg =
|
const bg =
|
||||||
@@ -175,11 +175,15 @@ const wrapperStyle = computed(() => {
|
|||||||
return {
|
return {
|
||||||
background: bg,
|
background: bg,
|
||||||
padding: `${rpx(res.paddingTop)} ${rpx(res.paddingX)} ${rpx(res.paddingBottom)}`,
|
padding: `${rpx(res.paddingTop)} ${rpx(res.paddingX)} ${rpx(res.paddingBottom)}`,
|
||||||
|
marginBottom: rpx(res.pageGap),
|
||||||
borderRadius: rpx(res.borderRadius),
|
borderRadius: rpx(res.borderRadius),
|
||||||
overflow: Number(res.borderRadius) > 0 ? "hidden" : "visible",
|
overflow: Number(res.borderRadius) > 0 ? "hidden" : "visible",
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
const listStyle = computed(() => ({ gap: rpx(props.res?.contentGap ?? 10) }));
|
const listStyle = computed(() => {
|
||||||
|
const gap = rpx(props.res?.contentGap ?? 10);
|
||||||
|
return { gap, "--g-gap": gap };
|
||||||
|
});
|
||||||
const itemStyle = computed(() => ({
|
const itemStyle = computed(() => ({
|
||||||
borderRadius: rpx(props.res?.contentRadius ?? 7),
|
borderRadius: rpx(props.res?.contentRadius ?? 7),
|
||||||
overflow: Number(props.res?.contentRadius ?? 7) > 0 ? "hidden" : "visible",
|
overflow: Number(props.res?.contentRadius ?? 7) > 0 ? "hidden" : "visible",
|
||||||
@@ -242,14 +246,15 @@ async function loadNewGoods(reset = true) {
|
|||||||
sales: g.buyCount != null ? g.buyCount : null,
|
sales: g.buyCount != null ? g.buyCount : null,
|
||||||
}));
|
}));
|
||||||
if (reset) {
|
if (reset) {
|
||||||
// 指定商品:按选择顺序排列
|
// 指定商品:按选择顺序排列(兼容 SKU id 与 goodsId)
|
||||||
if (first.value.dataMode === "goods") {
|
if (first.value.dataMode === "goods") {
|
||||||
const byGoodsId: Record<string, any> = {};
|
const byId: Record<string, any> = {};
|
||||||
mapped.forEach((g: any) => {
|
mapped.forEach((g: any) => {
|
||||||
byGoodsId[g.goodsId] = g;
|
if (g.id) byId[g.id] = g;
|
||||||
|
if (g.goodsId) byId[g.goodsId] = g;
|
||||||
});
|
});
|
||||||
newGoodsData.value = (first.value.goodsList || [])
|
newGoodsData.value = (first.value.goodsList || [])
|
||||||
.map((g: any) => byGoodsId[g.id])
|
.map((g: any) => byId[g.id] || byId[g.goodsId])
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
} else {
|
} else {
|
||||||
newGoodsData.value = mapped;
|
newGoodsData.value = mapped;
|
||||||
@@ -479,41 +484,62 @@ $w_94: 94%;
|
|||||||
|
|
||||||
.cart-plus,
|
.cart-plus,
|
||||||
.cart-cart {
|
.cart-cart {
|
||||||
width: 36rpx;
|
width: 48rpx;
|
||||||
height: 36rpx;
|
height: 48rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cart-plus-label {
|
.cart-plus-label {
|
||||||
font-size: 28rpx;
|
font-size: 30rpx;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cart-text {
|
.cart-text {
|
||||||
border-radius: 18rpx;
|
border-radius: 24rpx;
|
||||||
padding: 4rpx 18rpx;
|
padding: 6rpx 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cart-text-label {
|
.cart-text-label {
|
||||||
font-size: 22rpx;
|
font-size: 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 卡片:左图右文 */
|
/* 卡片:左图右文(参考 CRMEB 详细列表,左侧 224rpx 缩略图,右侧标题置顶、价格销量置底) */
|
||||||
.mode-card {
|
.mode-card {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
.g-item {
|
.g-item {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: stretch;
|
||||||
padding: 16rpx;
|
padding: 20rpx;
|
||||||
}
|
}
|
||||||
.g-imgbox {
|
.g-imgbox {
|
||||||
width: 140rpx;
|
width: 224rpx;
|
||||||
height: 140rpx;
|
height: 224rpx;
|
||||||
margin-right: 16rpx;
|
margin-right: 24rpx;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.g-info {
|
||||||
|
min-height: 224rpx;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
.g-name {
|
.g-name {
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 40rpx;
|
||||||
|
margin-bottom: 12rpx;
|
||||||
|
}
|
||||||
|
.g-price {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-top: auto;
|
||||||
margin-bottom: 8rpx;
|
margin-bottom: 8rpx;
|
||||||
}
|
}
|
||||||
|
.g-bottom {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
.g-sales {
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
.g-cart {
|
.g-cart {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
@@ -522,7 +548,7 @@ $w_94: 94%;
|
|||||||
/* 列表:两列网格 */
|
/* 列表:两列网格 */
|
||||||
.mode-list {
|
.mode-list {
|
||||||
.g-item {
|
.g-item {
|
||||||
width: calc(50% - 10rpx);
|
width: calc((100% - var(--g-gap, 10rpx)) / 2);
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.g-imgbox {
|
.g-imgbox {
|
||||||
@@ -541,7 +567,7 @@ $w_94: 94%;
|
|||||||
/* 三列 */
|
/* 三列 */
|
||||||
.mode-three {
|
.mode-three {
|
||||||
.g-item {
|
.g-item {
|
||||||
width: calc(33.33% - 12rpx);
|
width: calc((100% - var(--g-gap, 10rpx) * 2) / 3);
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.g-imgbox {
|
.g-imgbox {
|
||||||
|
|||||||
497
pages/tabbar/home/template/tpl_home_comb.vue
Normal file
497
pages/tabbar/home/template/tpl_home_comb.vue
Normal file
@@ -0,0 +1,497 @@
|
|||||||
|
<template>
|
||||||
|
<view class="tpl-home-comb" :style="wrapperStyle">
|
||||||
|
<!-- 高斯模糊轮播图背景 + 底部渐变遮罩 -->
|
||||||
|
<view class="comb-bg">
|
||||||
|
<image
|
||||||
|
v-if="currentBannerImg"
|
||||||
|
class="comb-bg-img"
|
||||||
|
:src="currentBannerImg"
|
||||||
|
mode="aspectFill"
|
||||||
|
/>
|
||||||
|
<view class="comb-mask"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 顶部状态栏占位(小程序/App) -->
|
||||||
|
<view v-if="statusBarHeight" :style="{ height: statusBarHeight + 'px' }"></view>
|
||||||
|
|
||||||
|
<!-- 1. 搜索栏 -->
|
||||||
|
<view class="comb-search-row" :style="searchRowStyle">
|
||||||
|
<image
|
||||||
|
v-if="res.searType === 'logo' && res.logoUrl"
|
||||||
|
class="comb-logo"
|
||||||
|
:src="res.logoUrl"
|
||||||
|
mode="aspectFit"
|
||||||
|
/>
|
||||||
|
<view class="comb-search-box" :style="searchBoxStyle" @click="onSearchTap">
|
||||||
|
<u-icon name="search" :color="res.textColor || '#303133'" size="28rpx" />
|
||||||
|
<text class="comb-search-text">{{ displayHotWord }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 2. 分类选项卡 -->
|
||||||
|
<view v-if="res.showTabs !== false" class="comb-tabs-wrap">
|
||||||
|
<view class="comb-tabs">
|
||||||
|
<scroll-view scroll-x class="comb-tabs-scroll" :show-scrollbar="false">
|
||||||
|
<view class="comb-tabs-inner">
|
||||||
|
<view
|
||||||
|
v-for="(tab, idx) in displayTabs"
|
||||||
|
:key="idx"
|
||||||
|
class="comb-tab-item"
|
||||||
|
:class="{ active: activeTabIndex === idx }"
|
||||||
|
:style="{
|
||||||
|
color:
|
||||||
|
activeTabIndex === idx
|
||||||
|
? res.tabActiveColor || '#E93323'
|
||||||
|
: res.tabColor || '#FFFFFF',
|
||||||
|
}"
|
||||||
|
@click="onTabTap(tab, idx)"
|
||||||
|
>
|
||||||
|
<text>{{ tab.title || "未命名" }}</text>
|
||||||
|
<view
|
||||||
|
v-if="activeTabIndex === idx"
|
||||||
|
class="comb-tab-line"
|
||||||
|
:style="{ background: res.tabActiveColor || '#E93323' }"
|
||||||
|
></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<view class="comb-tab-toggle" @click="showMoreTabs = !showMoreTabs">
|
||||||
|
<u-icon
|
||||||
|
:name="showMoreTabs ? 'arrow-up' : 'arrow-down'"
|
||||||
|
:color="res.tabColor || '#FFFFFF'"
|
||||||
|
size="28rpx"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 下拉展开全部分类面板 -->
|
||||||
|
<view v-if="showMoreTabs" class="comb-tabs-dropdown">
|
||||||
|
<view
|
||||||
|
v-for="(tab, idx) in displayTabs"
|
||||||
|
:key="idx"
|
||||||
|
class="dropdown-chip"
|
||||||
|
:class="{ active: activeTabIndex === idx }"
|
||||||
|
:style="
|
||||||
|
activeTabIndex === idx
|
||||||
|
? {
|
||||||
|
color: res.tabActiveColor || '#E93323',
|
||||||
|
borderColor: res.tabActiveColor || '#E93323',
|
||||||
|
}
|
||||||
|
: {}
|
||||||
|
"
|
||||||
|
@click="onTabTap(tab, idx)"
|
||||||
|
>
|
||||||
|
{{ tab.title || "未命名" }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 3. 轮播图区域 -->
|
||||||
|
<view
|
||||||
|
v-if="bannerList.length"
|
||||||
|
class="comb-banner"
|
||||||
|
:class="{ 'no-tabs': res.showTabs === false }"
|
||||||
|
>
|
||||||
|
<swiper
|
||||||
|
class="comb-swiper"
|
||||||
|
autoplay
|
||||||
|
:interval="4500"
|
||||||
|
:duration="500"
|
||||||
|
circular
|
||||||
|
:previous-margin="cardMode ? '48rpx' : '0rpx'"
|
||||||
|
:next-margin="cardMode ? '48rpx' : '0rpx'"
|
||||||
|
@change="onSwiperChange"
|
||||||
|
>
|
||||||
|
<swiper-item v-for="(item, i) in bannerList" :key="i">
|
||||||
|
<view
|
||||||
|
class="comb-slide-item"
|
||||||
|
:class="{ 'is-card': cardMode, active: i === currentSlide }"
|
||||||
|
@click="onBannerTap(item)"
|
||||||
|
>
|
||||||
|
<image
|
||||||
|
class="comb-slide-img"
|
||||||
|
:style="bannerImgStyle"
|
||||||
|
:src="item.img"
|
||||||
|
mode="scaleToFill"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</swiper-item>
|
||||||
|
</swiper>
|
||||||
|
|
||||||
|
<!-- 指示器 -->
|
||||||
|
<view
|
||||||
|
v-if="res.indicatorStyle !== 'none' && bannerList.length > 1"
|
||||||
|
class="comb-indicator"
|
||||||
|
:class="'pos-' + (res.indicatorPosition || 'center')"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
v-for="(item, i) in bannerList"
|
||||||
|
:key="i"
|
||||||
|
class="dot"
|
||||||
|
:class="[res.indicatorStyle || 'round', { active: i === currentSlide }]"
|
||||||
|
:style="
|
||||||
|
i === currentSlide
|
||||||
|
? { background: res.indicatorColor || '#E93323' }
|
||||||
|
: {}
|
||||||
|
"
|
||||||
|
></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, watch, onMounted, onBeforeUnmount } from "vue";
|
||||||
|
import { modelNavigateTo } from "./tpl";
|
||||||
|
|
||||||
|
const props = defineProps<{ res: any }>();
|
||||||
|
|
||||||
|
const toRpx = (v: any) => `${Number(v) || 0}rpx`;
|
||||||
|
|
||||||
|
// 状态栏与胶囊避让
|
||||||
|
const statusBarHeight = ref(0);
|
||||||
|
const capsuleRightPad = ref(0);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
try {
|
||||||
|
const info = uni.getWindowInfo();
|
||||||
|
// #ifdef MP-WEIXIN || APP-PLUS
|
||||||
|
statusBarHeight.value = info.statusBarHeight || 0;
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
const menu = uni.getMenuButtonBoundingClientRect();
|
||||||
|
capsuleRightPad.value = Math.max(0, info.windowWidth - menu.left + 8);
|
||||||
|
// #endif
|
||||||
|
} catch (e) {
|
||||||
|
statusBarHeight.value = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 搜索热词轮换
|
||||||
|
const hotIndex = ref(0);
|
||||||
|
let hotTimer: ReturnType<typeof setInterval> | null = null;
|
||||||
|
const validHotWords = computed(() =>
|
||||||
|
(props.res?.hotWords || []).filter((w: string) => w && String(w).trim())
|
||||||
|
);
|
||||||
|
const displayHotWord = computed(() => {
|
||||||
|
if (validHotWords.value.length) {
|
||||||
|
return validHotWords.value[hotIndex.value % validHotWords.value.length];
|
||||||
|
}
|
||||||
|
return props.res?.placeWords || "搜索商品名称";
|
||||||
|
});
|
||||||
|
|
||||||
|
function stopHotTimer() {
|
||||||
|
if (hotTimer) {
|
||||||
|
clearInterval(hotTimer);
|
||||||
|
hotTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => [validHotWords.value.length, props.res?.hotInterval],
|
||||||
|
() => {
|
||||||
|
stopHotTimer();
|
||||||
|
hotIndex.value = 0;
|
||||||
|
if (validHotWords.value.length > 1) {
|
||||||
|
hotTimer = setInterval(() => {
|
||||||
|
hotIndex.value = (hotIndex.value + 1) % validHotWords.value.length;
|
||||||
|
}, (Number(props.res?.hotInterval) || 3) * 1000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
onBeforeUnmount(stopHotTimer);
|
||||||
|
|
||||||
|
// 选项卡
|
||||||
|
const activeTabIndex = ref(0);
|
||||||
|
const showMoreTabs = ref(false);
|
||||||
|
const displayTabs = computed(() => {
|
||||||
|
const custom = Array.isArray(props.res?.tabList) ? props.res.tabList : [];
|
||||||
|
return [{ title: "首页", isHome: true }, ...custom];
|
||||||
|
});
|
||||||
|
|
||||||
|
function onTabTap(tab: any, idx: number) {
|
||||||
|
activeTabIndex.value = idx;
|
||||||
|
showMoreTabs.value = false;
|
||||||
|
if (tab.isHome || !tab.value) return;
|
||||||
|
if (tab.dataType === "special") {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/tabbar/special/special?id=${tab.value}`,
|
||||||
|
});
|
||||||
|
} else if (tab.dataType === "category") {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/navigation/search/searchPage?category=${tab.value}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 轮播图
|
||||||
|
const currentSlide = ref(0);
|
||||||
|
const bannerList = computed(() =>
|
||||||
|
Array.isArray(props.res?.list) ? props.res.list : []
|
||||||
|
);
|
||||||
|
const cardMode = computed(() => (props.res?.swiperStyle || "card") === "card");
|
||||||
|
const currentBannerImg = computed(() => {
|
||||||
|
const list = bannerList.value;
|
||||||
|
if (!list.length) return "";
|
||||||
|
const item = list[currentSlide.value % list.length] || list[0];
|
||||||
|
return item?.img || "";
|
||||||
|
});
|
||||||
|
|
||||||
|
function onSwiperChange(e: any) {
|
||||||
|
currentSlide.value = e?.detail?.current ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBannerTap(item: any) {
|
||||||
|
if (item) modelNavigateTo(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSearchTap() {
|
||||||
|
const keyword = validHotWords.value.length ? displayHotWord.value : "";
|
||||||
|
const query = keyword ? `?keyword=${encodeURIComponent(keyword)}` : "";
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/navigation/search/searchPage${query}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 样式计算
|
||||||
|
const wrapperStyle = computed(() => ({
|
||||||
|
marginBottom: toRpx(props.res?.pageGap ?? 0),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const searchRowStyle = computed(() =>
|
||||||
|
capsuleRightPad.value ? { paddingRight: `${capsuleRightPad.value}px` } : {}
|
||||||
|
);
|
||||||
|
|
||||||
|
const searchBoxStyle = computed(() => {
|
||||||
|
const r = props.res || {};
|
||||||
|
const align = r.textAlign || "left";
|
||||||
|
return {
|
||||||
|
background: r.boxColor || "#FFFFFF",
|
||||||
|
color: r.textColor || "#303133",
|
||||||
|
borderRadius: toRpx(r.searchRadius ?? 30),
|
||||||
|
justifyContent:
|
||||||
|
align === "center"
|
||||||
|
? "center"
|
||||||
|
: align === "right"
|
||||||
|
? "flex-end"
|
||||||
|
: "flex-start",
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const bannerImgStyle = computed(() => ({
|
||||||
|
borderRadius: toRpx(props.res?.bannerRadius ?? 14),
|
||||||
|
}));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.tpl-home-comb {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 16rpx 20rpx 20rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-bg {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background: linear-gradient(180deg, #e93323 0%, #f5f5f5 100%);
|
||||||
|
.comb-bg-img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
transform: scale(1.25);
|
||||||
|
filter: blur(40rpx);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.comb-mask {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
height: 180rpx;
|
||||||
|
background: linear-gradient(180deg, rgba(245, 245, 245, 0) 0%, #f5f5f5 100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-search-row {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-logo {
|
||||||
|
width: 138rpx;
|
||||||
|
height: 48rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-search-box {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
height: 60rpx;
|
||||||
|
padding: 0 20rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-search-text {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-tabs-wrap {
|
||||||
|
position: relative;
|
||||||
|
z-index: 3;
|
||||||
|
margin-top: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-tabs {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 72rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-tabs-scroll {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-tabs-inner {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-tab-item {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 68rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
white-space: nowrap;
|
||||||
|
&.active {
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.comb-tab-line {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
bottom: 4rpx;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 36rpx;
|
||||||
|
height: 4rpx;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-tab-toggle {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding-left: 16rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-tabs-dropdown {
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
margin-top: 8rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16rpx;
|
||||||
|
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-chip {
|
||||||
|
padding: 8rpx 24rpx;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border: 2rpx solid transparent;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-banner {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
margin-top: 12rpx;
|
||||||
|
height: 300rpx;
|
||||||
|
&.no-tabs {
|
||||||
|
margin-top: 20rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-swiper {
|
||||||
|
width: 100%;
|
||||||
|
height: 300rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-slide-item {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
&.is-card {
|
||||||
|
padding: 0 8rpx;
|
||||||
|
transform: scale(0.92);
|
||||||
|
transition: transform 0.35s ease;
|
||||||
|
&.active {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-slide-img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comb-indicator {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 16rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 3;
|
||||||
|
&.pos-left {
|
||||||
|
left: 32rpx;
|
||||||
|
}
|
||||||
|
&.pos-center {
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
&.pos-right {
|
||||||
|
right: 32rpx;
|
||||||
|
}
|
||||||
|
.dot {
|
||||||
|
background: rgba(255, 255, 255, 0.65);
|
||||||
|
transition: all 0.25s ease;
|
||||||
|
&.round {
|
||||||
|
width: 12rpx;
|
||||||
|
height: 12rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin: 0 6rpx;
|
||||||
|
}
|
||||||
|
&.line {
|
||||||
|
width: 24rpx;
|
||||||
|
height: 6rpx;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
margin: 0 4rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 样式一:两列大卡片 -->
|
<!-- 样式一:两列大卡片 -->
|
||||||
<view v-else-if="layoutStyle === '1'" class="ig-grid2">
|
<view v-else-if="layoutStyle === '1'" class="ig-grid2" :style="gapStyle">
|
||||||
<view
|
<view
|
||||||
class="ig-g2-item"
|
class="ig-g2-item"
|
||||||
v-for="(item, index) in goodsList"
|
v-for="(item, index) in goodsList"
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
<view class="ig-g2-img-box" :style="imgRadiusStyle">
|
<view class="ig-g2-img-box" :style="imgRadiusStyle">
|
||||||
<image class="ig-img" :src="item.goodsImage || item.thumbnail" mode="aspectFill" />
|
<image class="ig-img" :src="item.goodsImage || item.thumbnail" mode="aspectFill" />
|
||||||
</view>
|
</view>
|
||||||
<view class="ig-g2-name">{{ item.goodsName || item.promotionName || '' }}</view>
|
<view class="ig-g2-name" :style="nameStyle">{{ item.goodsName || item.promotionName || '' }}</view>
|
||||||
<view class="ig-price-row">
|
<view class="ig-price-row">
|
||||||
<view class="ig-price" :style="pointStyle">
|
<view class="ig-price" :style="pointStyle">
|
||||||
<text class="ig-coin">¥</text>{{ item.points != null ? item.points : 0 }}积分
|
<text class="ig-coin">¥</text>{{ item.points != null ? item.points : 0 }}积分
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 样式二:三列,积分价在名称上方 -->
|
<!-- 样式二:三列,积分价在名称上方 -->
|
||||||
<view v-else-if="layoutStyle === '2'" class="ig-grid3">
|
<view v-else-if="layoutStyle === '2'" class="ig-grid3" :style="gapStyle">
|
||||||
<view
|
<view
|
||||||
class="ig-g3-item"
|
class="ig-g3-item"
|
||||||
v-for="(item, index) in goodsList"
|
v-for="(item, index) in goodsList"
|
||||||
@@ -69,11 +69,11 @@
|
|||||||
<view class="ig-price ig-price-sm" :style="pointStyle">
|
<view class="ig-price ig-price-sm" :style="pointStyle">
|
||||||
<text class="ig-coin ig-coin-sm">¥</text>{{ item.points != null ? item.points : 0 }}积分
|
<text class="ig-coin ig-coin-sm">¥</text>{{ item.points != null ? item.points : 0 }}积分
|
||||||
</view>
|
</view>
|
||||||
<view class="ig-g3-name">{{ item.goodsName || item.promotionName || '' }}</view>
|
<view class="ig-g3-name" :style="nameStyle">{{ item.goodsName || item.promotionName || '' }}</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 样式三:三列,仅积分价 -->
|
<!-- 样式三:三列,仅积分价 -->
|
||||||
<view v-else class="ig-grid3">
|
<view v-else class="ig-grid3" :style="gapStyle">
|
||||||
<view
|
<view
|
||||||
class="ig-g3-item"
|
class="ig-g3-item"
|
||||||
v-for="(item, index) in goodsList"
|
v-for="(item, index) in goodsList"
|
||||||
@@ -136,7 +136,9 @@ const headStyle = computed(() => {
|
|||||||
const res = props.res;
|
const res = props.res;
|
||||||
if (res.headBgType === "image" && res.headBgImage) {
|
if (res.headBgType === "image" && res.headBgImage) {
|
||||||
return {
|
return {
|
||||||
backgroundImage: `url(${res.headBgImage});background-size:cover;background-position:center;`,
|
backgroundImage: `url(${res.headBgImage})`,
|
||||||
|
backgroundSize: "cover",
|
||||||
|
backgroundPosition: "center",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const bg =
|
const bg =
|
||||||
@@ -162,9 +164,14 @@ const moreStyle = computed(() =>
|
|||||||
const pointStyle = computed(() =>
|
const pointStyle = computed(() =>
|
||||||
styled.value && props.res.pointColor ? { color: props.res.pointColor } : {}
|
styled.value && props.res.pointColor ? { color: props.res.pointColor } : {}
|
||||||
);
|
);
|
||||||
const gapStyle = computed(() =>
|
const nameStyle = computed(() =>
|
||||||
styled.value ? { gap: `${Number(props.res.contentGap) || 0}rpx` } : {}
|
styled.value && props.res.nameColor ? { color: props.res.nameColor } : {}
|
||||||
);
|
);
|
||||||
|
const gapStyle = computed(() => {
|
||||||
|
if (!styled.value) return {};
|
||||||
|
const gap = `${Number(props.res.contentGap ?? 10) || 0}rpx`;
|
||||||
|
return { gap, "--ig-gap": gap };
|
||||||
|
});
|
||||||
const imgRadiusStyle = computed(() =>
|
const imgRadiusStyle = computed(() =>
|
||||||
styled.value ? { borderRadius: `${Number(props.res.imgRadius) || 0}rpx`, overflow: "hidden" } : {}
|
styled.value ? { borderRadius: `${Number(props.res.imgRadius) || 0}rpx`, overflow: "hidden" } : {}
|
||||||
);
|
);
|
||||||
@@ -252,16 +259,14 @@ function goDetail(item: any) {
|
|||||||
.ig-grid2 {
|
.ig-grid2 {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: space-between;
|
|
||||||
}
|
}
|
||||||
.ig-g2-item {
|
.ig-g2-item {
|
||||||
width: 49%;
|
width: calc((100% - var(--ig-gap, 10rpx)) / 2);
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 16rpx;
|
border-radius: 16rpx;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding-bottom: 16rpx;
|
padding-bottom: 16rpx;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin-bottom: 16rpx;
|
|
||||||
}
|
}
|
||||||
.ig-g2-img-box {
|
.ig-g2-img-box {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -323,16 +328,14 @@ function goDetail(item: any) {
|
|||||||
.ig-grid3 {
|
.ig-grid3 {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: space-between;
|
|
||||||
}
|
}
|
||||||
.ig-g3-item {
|
.ig-g3-item {
|
||||||
width: 32.5%;
|
width: calc((100% - var(--ig-gap, 10rpx) * 2) / 3);
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 16rpx;
|
border-radius: 16rpx;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding-bottom: 16rpx;
|
padding-bottom: 16rpx;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin-bottom: 16rpx;
|
|
||||||
}
|
}
|
||||||
.ig-g3-img-box {
|
.ig-g3-img-box {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="wrapper">
|
<div class="wrapper" :style="pageBgStyle">
|
||||||
<!-- uni 中不能使用 vue component 所以用if判断每个组件 -->
|
<!-- uni 中不能使用 vue component 所以用if判断每个组件 -->
|
||||||
<div v-for="(item, index) in pageData.list" :key="index">
|
<div v-for="(item, index) in pageData.list" :key="index">
|
||||||
<!-- 搜索栏,如果在楼层装修顶部则会自动浮动,否则不浮动 -->
|
<!-- 搜索栏,如果在楼层装修顶部则会自动浮动,否则不浮动 -->
|
||||||
<div class="navbar" v-if="item.type == 'search'">
|
<div class="navbar" v-if="item.type == 'search'" :style="{ background: topColor }">
|
||||||
<search style="width: 100%" :res="item.options" />
|
<search style="width: 100%" :res="item.options" />
|
||||||
<!-- #ifndef H5 -->
|
<!-- #ifndef H5 -->
|
||||||
<!-- 扫码功能 不兼容h5 详情文档: https://uniapp.dcloud.io/api/system/barcode?id=scancode -->
|
<!-- 扫码功能 不兼容h5 详情文档: https://uniapp.dcloud.io/api/system/barcode?id=scancode -->
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
</div>
|
</div>
|
||||||
|
<homeComb v-if="item.type == 'homeComb'" :res="item.options" />
|
||||||
<carousel v-if="item.type == 'carousel'" :res="item.options" />
|
<carousel v-if="item.type == 'carousel'" :res="item.options" />
|
||||||
<titleLayout v-if="item.type == 'title'" :res="item.options" />
|
<titleLayout v-if="item.type == 'title'" :res="item.options" />
|
||||||
<leftOneRightTwo
|
<leftOneRightTwo
|
||||||
@@ -56,7 +57,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import carousel from '@/pages/tabbar/home/template/tpl_banner'
|
import carousel from '@/pages/tabbar/home/template/tpl_banner'
|
||||||
import titleLayout from '@/pages/tabbar/home/template/tpl_title'
|
import titleLayout from '@/pages/tabbar/home/template/tpl_title'
|
||||||
@@ -84,6 +85,7 @@ import integral from '@/pages/tabbar/home/template/tpl_integral'
|
|||||||
import coupon from '@/pages/tabbar/home/template/tpl_coupon'
|
import coupon from '@/pages/tabbar/home/template/tpl_coupon'
|
||||||
import articleList from '@/pages/tabbar/home/template/tpl_article'
|
import articleList from '@/pages/tabbar/home/template/tpl_article'
|
||||||
import shopList from '@/pages/tabbar/home/template/tpl_shop'
|
import shopList from '@/pages/tabbar/home/template/tpl_shop'
|
||||||
|
import homeComb from '@/pages/tabbar/home/template/tpl_home_comb.vue'
|
||||||
import { toSpecial, getSpecial } from '@/api/home'
|
import { toSpecial, getSpecial } from '@/api/home'
|
||||||
import permision from '@/js_sdk/wa-permission/permission.js'
|
import permision from '@/js_sdk/wa-permission/permission.js'
|
||||||
import config from '@/config/config'
|
import config from '@/config/config'
|
||||||
@@ -93,6 +95,42 @@ const pageData = ref<any>('')
|
|||||||
const bodyParam = ref('')
|
const bodyParam = ref('')
|
||||||
const isIos = ref('')
|
const isIos = ref('')
|
||||||
|
|
||||||
|
const topColor = computed(() => pageData.value?.topColor || '#ffffff')
|
||||||
|
const pageBgStyle = computed(() => {
|
||||||
|
const data: any = pageData.value
|
||||||
|
if (data?.bgType === 'image' && data?.bgImage) {
|
||||||
|
const size =
|
||||||
|
data.bgFill === 'contain'
|
||||||
|
? 'contain'
|
||||||
|
: data.bgFill === 'cover'
|
||||||
|
? 'cover'
|
||||||
|
: '100% 100%'
|
||||||
|
return {
|
||||||
|
backgroundImage: `url(${data.bgImage})`,
|
||||||
|
backgroundSize: size,
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
backgroundColor: data.bgColor || '#f9f9f9',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data?.bgColor) {
|
||||||
|
return { backgroundColor: data.bgColor }
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
})
|
||||||
|
|
||||||
|
function applyPageSettings(parsed: any) {
|
||||||
|
if (!parsed) return
|
||||||
|
if (parsed.title) {
|
||||||
|
uni.setNavigationBarTitle({ title: parsed.title })
|
||||||
|
}
|
||||||
|
if (parsed.topColor || parsed.titleColor) {
|
||||||
|
uni.setNavigationBarColor({
|
||||||
|
frontColor: parsed.titleColor === 'white' ? '#ffffff' : '#000000',
|
||||||
|
backgroundColor: parsed.topColor || '#ffffff',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
init()
|
init()
|
||||||
// #ifdef MP-WEIXIN
|
// #ifdef MP-WEIXIN
|
||||||
@@ -116,6 +154,7 @@ function init() {
|
|||||||
parsed.list = parsed.list.filter((i: any) => !i?.hidden)
|
parsed.list = parsed.list.filter((i: any) => !i?.hidden)
|
||||||
}
|
}
|
||||||
pageData.value = parsed
|
pageData.value = parsed
|
||||||
|
applyPageSettings(parsed)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@@ -126,6 +165,7 @@ function init() {
|
|||||||
parsed.list = parsed.list.filter((i: any) => !i?.hidden)
|
parsed.list = parsed.list.filter((i: any) => !i?.hidden)
|
||||||
}
|
}
|
||||||
pageData.value = parsed
|
pageData.value = parsed
|
||||||
|
applyPageSettings(parsed)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -211,4 +251,4 @@ async function scan() {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user