481 lines
16 KiB
Vue
481 lines
16 KiB
Vue
<template>
|
||
<view class="container">
|
||
<view class="main">
|
||
<z-paging
|
||
ref="paging"
|
||
v-model="indexDataArr"
|
||
@query="upCallback"
|
||
@scroll="pagingScroll"
|
||
@scrolltoupper="scrolltoupper"
|
||
:fixed="false"
|
||
height="100%"
|
||
auto-show-back-to-top
|
||
>
|
||
<view class="top_container">
|
||
<view
|
||
class="title text-[#1b4694] font-bold text-5xl"
|
||
:style="{
|
||
top: statusBarHeight + 'px',
|
||
height: navHeight + 'px',
|
||
lineHeight: navHeight + 'px'
|
||
}"
|
||
>
|
||
{{ titleImageObj[0]?.content?.title ?? '思缘生活' }}
|
||
</view>
|
||
<template v-if="searchList">
|
||
<w-search
|
||
:content="searchList?.content"
|
||
:styles="searchList?.styles"
|
||
:navbarStyle="{ top: titleHeight + 10 + 'px' }"
|
||
/>
|
||
</template>
|
||
<image
|
||
:style="{ height: 70 + titleHeight + 'px' }"
|
||
:src="getImageUrl(item.image)"
|
||
v-for="(item, ind) in titleImageObj[0]?.content?.data"
|
||
:key="ind"
|
||
/>
|
||
</view>
|
||
<!-- 固定顶部搜索栏 -->
|
||
<view
|
||
class="top_fixed fixed bg-white w-[100%] top-0 z-[99]"
|
||
:style="{ height: titleHeight + 8 + 'px' }"
|
||
v-if="searchFixed"
|
||
>
|
||
<template v-if="searchList">
|
||
<w-search
|
||
:content="searchList?.content"
|
||
:styles="searchList?.styles"
|
||
:navbarStyle="{ bottom: '13px', height: capsuleHeight + 'px' }"
|
||
:navbarItemStyle="{ background: '#F1F1F1' }"
|
||
:inputStyle="{ width: '250rpx' }"
|
||
/>
|
||
</template>
|
||
</view>
|
||
|
||
<view>
|
||
<view
|
||
v-for="(item, index) in indexData.pages"
|
||
:key="index"
|
||
class="bg-[#F5F5F7]"
|
||
>
|
||
<!-- <template v-if="item.name == 'search'">
|
||
<w-search :content="item.content" :styles="item.styles" />
|
||
</template> -->
|
||
<template v-if="item.name == 'banner'">
|
||
<w-banner :content="item.content" :styles="item.styles" />
|
||
</template>
|
||
<template v-if="item.name == 'nav'">
|
||
<w-nav :content="item.content" :styles="item.styles" />
|
||
</template>
|
||
<template v-if="item.name == 'category'">
|
||
<w-category :content="item.content" :styles="item.styles" />
|
||
</template>
|
||
</view>
|
||
<template v-if="activityList?.length">
|
||
<ActivateIndoor :lists="activityList"></ActivateIndoor>
|
||
</template>
|
||
<!-- 页面展示需要把活动专区放在推荐分类列表和分类服务中间,所以这里要抽离出来重新写 -->
|
||
<view
|
||
v-for="(item, index) in indexData.pages"
|
||
:key="index"
|
||
class="bg-[#F5F5F7]"
|
||
>
|
||
<template v-if="item.name == 'category'">
|
||
<CategoryDatalist :content="item.content" />
|
||
</template>
|
||
</view>
|
||
</view>
|
||
<!-- 活动专区:假节日搞活动 -->
|
||
<!-- <template v-if="indexData?.promotion?.length">
|
||
<ActivateIndoor :lists="indexData.promotion"></ActivateIndoor>
|
||
</template> -->
|
||
|
||
<!-- 新品推荐 -->
|
||
<!-- <template v-if="indexData?.newRecommend?.length">
|
||
<NewGoods :lists="indexData.newRecommend"></NewGoods>
|
||
</template> -->
|
||
|
||
<!-- 热门服务 -->
|
||
<!-- <template v-if="indexData?.hotService?.length">
|
||
<hot :lists="indexData.hotService"></hot>
|
||
</template> -->
|
||
<!-- 吸顶分类 -->
|
||
<template v-if="categoryList?.length > 0">
|
||
<stickyCategory
|
||
ref="stickycategory"
|
||
:lists="categoryList"
|
||
:top="titleHeight"
|
||
@tabChange="tabChange"
|
||
:isFixed="isFixed"
|
||
></stickyCategory>
|
||
</template>
|
||
|
||
<!-- 师傅推荐 暂时屏掉,参考竞品,一般不显示 -->
|
||
<!-- <template v-if="indexData?.staff?.length">
|
||
<master :lists="indexData.staff"></master>
|
||
</template> -->
|
||
|
||
<!-- 推荐分类 -->
|
||
<!-- <template v-if="indexData?.category.length || []">
|
||
<category :lists="indexData?.category"></category>
|
||
</template> -->
|
||
|
||
<!-- 用于占位 -->
|
||
<div class="cat" v-if="indexData?.hotService.length"></div>
|
||
</z-paging>
|
||
</view>
|
||
<view class="right-btns">
|
||
<view class="rightcontrol" @click="rightControl">
|
||
<!-- <image
|
||
class="iamge-close"
|
||
src="@/static/images/icon_clear.png"
|
||
alt=""
|
||
v-if="isShowRightBtn"
|
||
/> -->
|
||
</view>
|
||
<!-- <view class="allBtn" v-if="isShowRightBtn">
|
||
<button class="button" type="default" open-type="share">
|
||
<image src="@/static/images/share.png" alt="" />
|
||
<view>分享</view>
|
||
</button>
|
||
<button class="button" type="default" @click="call">
|
||
<image src="@/static/images/phone.png" alt="" />
|
||
<view>电话</view>
|
||
</button>
|
||
<button class="button" type="default" open-type="contact">
|
||
<image src="@/static/images/kefu.png" alt="" />
|
||
<view>客服</view>
|
||
</button>
|
||
</view> -->
|
||
</view>
|
||
<view class="endrightcontrol" @click="rightControl">
|
||
<image src="@/static/images/icon_user_about.png" alt="" v-if="!isShowRightBtn" />
|
||
</view>
|
||
<!-- 底部导航栏 -->
|
||
<Tabbar />
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { getIndex } from '@/api/shop'
|
||
import { reactive, shallowRef, ref, unref } from 'vue'
|
||
import { onLoad, onUnload, onShareAppMessage, onShow } from '@dcloudio/uni-app'
|
||
import Tabbar from '@/components/tabbar/tabbar.vue'
|
||
// import Category from './comp/category.vue'
|
||
import ActivateIndoor from './comp/activate-indoor.vue'
|
||
// import NewGoods from './comp/new-goods.vue'
|
||
// import Hot from './comp/hot-list.vue'
|
||
// import Master from './comp/master-list.vue'
|
||
import CategoryDatalist from './comp/category-datalist.vue'
|
||
import stickyCategory from './comp/sticky-category.vue'
|
||
import { useAppStore } from '@/stores/app'
|
||
import { getDecorate } from '@/api/shop'
|
||
import { useUserStore } from '@/stores/user'
|
||
import { apiActivityList } from '@/api/goods'
|
||
import { storeToRefs } from 'pinia'
|
||
|
||
const appStore = useAppStore()
|
||
const userStore = useUserStore()
|
||
const { userInfo } = storeToRefs(userStore)
|
||
const paging = shallowRef()
|
||
const { getImageUrl } = useAppStore()
|
||
const indexData = reactive<any>({
|
||
pages: [],
|
||
promotion: [],
|
||
newRecommend: [],
|
||
hotService: [],
|
||
staff: [],
|
||
category: []
|
||
})
|
||
interface ListContent {
|
||
content?: {
|
||
title: ''
|
||
data: [
|
||
{
|
||
image: ''
|
||
}
|
||
]
|
||
}
|
||
styles?: {}
|
||
title?: ''
|
||
}
|
||
interface ListContentList {
|
||
[index: number]: ListContent
|
||
}
|
||
interface ActivityList {
|
||
goodsIds: string | null
|
||
id: number
|
||
name: string
|
||
status: number
|
||
surfacePlot: string
|
||
}
|
||
let categoryList = reactive([]) //分类
|
||
let searchList = reactive<ListContent>({}) //搜索
|
||
const activityList = ref<ActivityList[]>([]) //活动专区
|
||
let titleImageObj = reactive<ListContentList>([]) //顶部图片标题
|
||
const titleHeight = ref(0) //标题栏总高度
|
||
const capsuleHeight = ref(0) //胶囊高度
|
||
const navHeight = ref(0) //导航栏高度
|
||
const statusBarHeight = ref(0) //状态栏高度
|
||
const getTitleHeight = () => {
|
||
const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
|
||
uni.getSystemInfo({
|
||
success: res => {
|
||
statusBarHeight.value = res?.statusBarHeight as number
|
||
navHeight.value =
|
||
(menuButtonInfo.top - statusBarHeight.value) * 2 + menuButtonInfo.height //获取导航栏高度
|
||
titleHeight.value = statusBarHeight.value + navHeight.value
|
||
capsuleHeight.value = menuButtonInfo.height
|
||
}
|
||
})
|
||
}
|
||
|
||
//z-paging直接绑定indexData控制台会报警告[Vue warn]: Invalid prop: type check failed for prop "modelValue". Expected Array, got Object
|
||
//故定义indexDataArr
|
||
interface IndexArray {
|
||
content: object
|
||
disabled: boolean
|
||
display: boolean
|
||
id: string
|
||
name: string
|
||
styles: object
|
||
title: string
|
||
}
|
||
let indexDataArr: IndexArray[] = []
|
||
const upCallback = async (): Promise<void> => {
|
||
try {
|
||
const data = await getIndex({
|
||
cityId: appStore.cityInfo.city_id
|
||
})
|
||
for (const key in indexData) {
|
||
if (data[key] != null && data[key] != undefined) {
|
||
indexData[key] = data[key]
|
||
}
|
||
}
|
||
indexData.pages = JSON.parse(data.pages)
|
||
indexDataArr = new Array(indexData.pages)
|
||
console.log('indexData.pages', indexData.pages)
|
||
|
||
// 吸顶分类列表
|
||
const cate_list = indexData.pages.filter((i: any) => i.name == 'sticky-category')
|
||
if (cate_list.length > 0) {
|
||
categoryList = cate_list[0].content.data
|
||
}
|
||
// 搜索栏
|
||
const search_list = indexData.pages.filter((i: any) => i.name == 'search')
|
||
if (search_list.length > 0) {
|
||
searchList = search_list[0]
|
||
}
|
||
// 顶部图片标题信息
|
||
titleImageObj = indexData.pages.filter((i: any) => i.name == 'home-title')
|
||
|
||
// 导航菜单(金刚区)
|
||
paging.value.complete([data])
|
||
} catch (err) {
|
||
console.log(err)
|
||
// refreshRef.value.endErr()
|
||
paging.value.complete(false)
|
||
}
|
||
}
|
||
|
||
onShow(async () => {
|
||
const res = await apiActivityList({ status: 1 })
|
||
activityList.value = res.lists
|
||
})
|
||
const stickycategory = ref()
|
||
const searchFixed = ref(false) //显示顶部搜索栏
|
||
const pagingScroll = async (e: any) => {
|
||
const banner_h = uni.upx2px(300) //300为顶部图片的高度
|
||
const sc_top = e.detail.scrollTop
|
||
stickycategory?.value?.handleActive(sc_top)
|
||
|
||
if (sc_top > banner_h) searchFixed.value = true
|
||
else searchFixed.value = false
|
||
}
|
||
|
||
const isFixed = ref(true)
|
||
const scrolltoupper = () => {
|
||
// 解决点击返回顶部按钮返回顶部后,还有吸顶的问题
|
||
isFixed.value = false
|
||
setTimeout(() => {
|
||
isFixed.value = true
|
||
})
|
||
}
|
||
// 吸顶分类改变
|
||
const tabChange = async (e: any) => {
|
||
paging.value.scrollToY(e)
|
||
}
|
||
|
||
onShareAppMessage(() => {
|
||
return {
|
||
title: `粤好生活`,
|
||
imageUrl: '',
|
||
path: `/pages/index/index?scene=${unref(userInfo).distributorId}`
|
||
}
|
||
})
|
||
const call = async () => {
|
||
// 获取页面装修-客服设置中配置的客服联系电话
|
||
const data = await getDecorate({ id: 3 })
|
||
const datas = JSON.parse(data.pages)
|
||
const mobile = datas[0].content.mobile
|
||
uni.makePhoneCall({
|
||
phoneNumber: mobile,
|
||
success: function () {
|
||
console.log('拨打电话成功')
|
||
},
|
||
fail: function () {
|
||
console.log('拨打电话失败')
|
||
}
|
||
})
|
||
}
|
||
|
||
// const sharedState = inject('sharedState')
|
||
|
||
onLoad(options => {
|
||
// 扫描普通二维码
|
||
// 有distId,重新扫码进来
|
||
// 有distId,重新扫新码
|
||
// #ifdef MP-WEIXIN
|
||
// const q = decodeURIComponent(options.q)
|
||
// if (q.indexOf('distributorId=') != -1) {
|
||
// // 已绑定且已登录
|
||
// if (userStore.distId && userStore.token) return
|
||
// const distributorId = parseFloat(q.split('distributorId=')[1])
|
||
// userStore.setDistId(distributorId)
|
||
// if (userStore.token) {
|
||
// userStore.bindingDistId()
|
||
// }
|
||
// }
|
||
|
||
// 扫太阳码或分享
|
||
const { scene } = options
|
||
if (scene) {
|
||
const distributorId = parseFloat(scene)
|
||
userStore.setDistId(distributorId)
|
||
if (userStore.token) {
|
||
userStore.bindingDistId()
|
||
}
|
||
}
|
||
|
||
// #endif
|
||
getTitleHeight()
|
||
uni.$on('refreshhome', () => {
|
||
upCallback()
|
||
})
|
||
})
|
||
|
||
onUnload(() => {
|
||
uni.$off('refreshhome')
|
||
})
|
||
|
||
const isShowRightBtn = ref(true)
|
||
const rightControl = () => {
|
||
isShowRightBtn.value = !isShowRightBtn.value
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.container {
|
||
display: flex;
|
||
height: 100vh;
|
||
overflow: hidden;
|
||
flex-direction: column;
|
||
font-family: 'Source Han Sans CN', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
|
||
|
||
.main {
|
||
flex: 1;
|
||
min-height: 0;
|
||
overflow: scroll;
|
||
background: #f8f8f9;
|
||
position: relative;
|
||
// background-color: #fff;
|
||
}
|
||
|
||
.top_container {
|
||
// position: absolute;
|
||
image {
|
||
width: 100%;
|
||
// height: 300rpx;
|
||
vertical-align: top;
|
||
}
|
||
|
||
.title {
|
||
position: absolute;
|
||
// top: 93rpx;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
}
|
||
}
|
||
|
||
.right-btns {
|
||
position: fixed;
|
||
right: 20rpx;
|
||
bottom: 25%;
|
||
width: 100rpx;
|
||
min-height: 35px;
|
||
z-index: 1000;
|
||
|
||
.rightcontrol {
|
||
width: 100%;
|
||
height: 50rpx;
|
||
display: flex;
|
||
|
||
image {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
object-fit: contain;
|
||
margin-left: auto;
|
||
}
|
||
|
||
.iamge-close {
|
||
background: rgba(34, 39, 21, 0.75);
|
||
border-radius: 50%;
|
||
}
|
||
}
|
||
|
||
.button {
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
background: rgba(34, 39, 21, 0.75);
|
||
border-radius: 50%;
|
||
margin-bottom: 20rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
color: #ffffff;
|
||
padding: 0;
|
||
|
||
image {
|
||
width: 35rpx;
|
||
height: 35rpx;
|
||
object-fit: contain;
|
||
}
|
||
|
||
view {
|
||
font-size: 24rpx;
|
||
height: 43rpx;
|
||
line-height: 43rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.endrightcontrol {
|
||
position: fixed;
|
||
right: 20rpx;
|
||
bottom: 168rpx;
|
||
width: 60rpx;
|
||
min-height: 40rpx;
|
||
z-index: 1000;
|
||
display: flex;
|
||
|
||
image {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
object-fit: contain;
|
||
}
|
||
}
|
||
}
|
||
</style>
|