Files
chazhi/src/pages/index/index.vue
wangxiaowei 716160c113 调试接口
2025-12-23 17:55:14 +08:00

352 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- 使用 type="home" 属性设置首页其他页面不需要设置默认为page -->
<route lang="jsonc" type="home">{
"layout": "tabbar",
"style": {
// 'custom' 表示开启自定义导航栏,默认 'default'
"navigationStyle": "custom",
"navigationBarTitleText": "首页"
}
}</route>
<template>
<view class="home-bg">
<view class="home-bg w-[100%] fixed top-0 left-0 z-100">
<wd-navbar safeAreaInsetTop :bordered="false" custom-style="background-color: transparent !important;">
<template #left>
<view class="flex items-center line-1 w-130rpx" @click="Index.handleToCity">
<view class="mr-10rpx font-400 leading-44rpx text-32rpx pl-10rpx line-1">{{ city || LOCATION_DEFAULT_CITY }}</view>
<wd-img width="14rpx" height="9rpx" :src="`${OSS}icon/icon_arrow_down.png`" />
</view>
</template>
<template #title>
<view class="search-box flex items-center ml-26rpx" @click="Index.handleToSearch">
<wd-search placeholder="搜索茶址名称" hide-cancel disabled :placeholder-left="true"
placeholderStyle="text-align:left;padding-left: 24rpx;line-heigt: 44rpx;color: #C9C9C9; font-size: 32rpx;font-weight: normal;">
</wd-search>
</view>
</template>
</wd-navbar>
</view>
<view :style="{ paddingTop: navbarHeight + 'px' }">
<view class="mt-32rpx mx-30rpx">
<wd-swiper height="240rpx" indicatorPosition="bottom-left"
:indicator="{ type: 'dots-bar' }" :list="swiperList" v-model:current="current" mode="aspectFit"></wd-swiper>
</view>
<view class="mt-40rpx flex items-center h-36rpx mx-30rpx">
<wd-img width="160rpx" height="36rpx" :src="`${OSS}images/home/home_image1.png`" mode="aspectFit" />
<text class="text-22rpx leading-32rpx text-[#818CA9] ml-36rpx">更多茶艺师点击预约</text>
</view>
<view class="mt-16rpx relative w-690rpx h-180rpx mx-30rpx" @click="Index.handleToWxOfficialAccount">
<wd-img width="690rpx" height="180rpx" :src="`${OSS}images/home/home_image2.png`" mode="scaleToFill" />
<view class="h-64rpx absolute bottom-0 right-0 bg-[#4C9F44] text-[#fff] flex items-center px-26rpx rounded">
<text class="mr-8rpx">一键约</text>
<wd-img width="22rpx" height="18.06rpx" :src="`${OSS}icon/icon_arrow_right.png`" mode="aspectFit" />
</view>
</view>
<view class="relative mt-40rpx h-44rpx mx-30rpx">
<view class="absolute ele-center" >
<wd-img width="252.04rpx" height="24.43rpx" :src="`${OSS}images/home/home_image3.png`" mode="aspectFit" />
</view>
<view class="text-32rpx text[#303133] font-500 absolute top-0 ele-center">预约茶室</view>
</view>
<view>
<mescroll-body @init="mescrollInit" :down="downOption" @down="downCallback" :up="upOption" @up="Index.upCallback" top="28rpx"
:fixed="true">
<view class="relative p-20rp mb-24rpx" v-for="(item, index) in list" :key="index" @click="Index.handleToReserveRoom(item.id, item.operation_type)">
<view class="absolute top--28rpx left-0 z-1" v-if="item.operation_type == 1">
<wd-img width="110rpx" height="110rpx" :src="`${OSS}images/home/home_image4.png`"/>
</view>
<view class="mx-30rpx p-30rpx flex bg-white rounded-10rpx">
<wd-img width="200rpx" height="200rpx" :src="item.image" radius="10rpx" />
<view class="flex-1 ml-28rpx flex justify-between line-1 items-start relative">
<view class="line-1">
<view class="font-bold text-30rpx leading-42rpx line-1">
{{ item.name }}
</view>
<view class="flex items-center mt-12rpx leading-34rpx">
<view class="font-400 text-[#F29747] text-24rpx mr-18rpx" v-if="item.operation_type == 1">半年预约{{ item.half_year_nums > 300 ? item.half_year_nums + '+' : item.half_year_nums }}</view>
<view class="font-400 bg-[#F3F3F3] text-[#818CA9] text-22rpx px-8rpx rounded-4rpx">刚有人预约了</view>
</view>
<view class="flex items-center mt-12rpx leading-34rpx">
<view class="font-400 text-[#606266] text-24rpx mr-10rpx">
营业时间:{{ item.start_time }}-{{ item.end_time }}
</view>
<view class="font-400 bg-[#FFEEED] text-[#FF5951] text-22rpx px-4rpx rounded-4rpx border-[#F2E2E1]" v-if="item.shop_status == 0">
打烊了
</view>
</view>
<view class="flex items-center mt-20rpx">
<wd-img width="26rpx" height="26rpx" :src="`${OSS}icon/icon_location.png`"
mode="aspectFit" />
<view class="ml-4rpx line-1 font-400 text-22rpx text-[#606266] leading-32rpx w-175rpx">
{{ item.address }}
</view>
</view>
</view>
<view class="absolute bottom-0 right-0">
<view class="flex justify-end">
<view class="bg-[#4C9F44] w-72rpx h-40rpx rounded-18rpx flex items-center justify-center">
<wd-icon name="add" color="#fff" size="20rpx" custom-style="font-weight: bold;" />
</view>
</view>
<view class="text-24rpx text-[#92928C] font-400 mt-12rpx">距您{{ item.distance }}km</view>
</view>
</view>
</view>
</view>
</mescroll-body>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import { router } from '@/utils/tools'
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
import useMescroll from "@/uni_modules/mescroll-uni/hooks/useMescroll.js"
import { LOCATION_DENY_TIME_KEY, handleEnsureLocationAuthHooks, LOCATION_DEFAULT_CITY, handleGetLocationCity, LOCATION_CITY_KEY } from '@/hooks/useLocation'
import { getHomeBannerList } from '@/api/home'
import { getHomeTeaStoreList } from '@/api/tea-room'
import { useUserStore } from '@/store'
const OSS = inject('OSS')
const navbarHeight = inject('navbarHeight')
/** 轮播图 **/
const swiperList = ref<string[]>([])
const current = ref<number>(0)
// 分页
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom) // 调用mescroll的hook
const downOption = {
auto: true
}
const upOption = {
auto: true,
textNoMore: '~ 已经到底啦 ~', //无更多数据的提示
}
const latitude = ref<number>(0)
const longitude = ref<number>(0)
const city = ref<string>('')
const keywords = ref<string>('')
const list = ref<Array<any>>([])
let lastLocation = { lat: 0, lng: 0 }
onShow(async () => {
if (uni.getStorageSync(LOCATION_DENY_TIME_KEY)) {
const location = await checkLocationAuthWithModal()
if (location) {
// 只有经纬度变化时才刷新
if (location.lat !== lastLocation.lat || location.lng !== lastLocation.lng) {
const loc = await handleGetLocationCity(location.lat, location.lng)
city.value = loc.city
latitude.value = location.lat
longitude.value = location.lng
lastLocation.lat = location.lat
lastLocation.lng = location.lng
console.log("🚀 ~ city.value:", 'xxxxx', city.value)
Index.handleResetSearch()
}
}
}
})
onLoad(async() => {
// 初始化页面数据
Index.handleInit()
// 获取用户经纬度(带缓存和授权逻辑)
const { lat, lng } = await handleEnsureLocationAuthHooks()
latitude.value = lat
longitude.value = lng
const location = await handleGetLocationCity(lat, lng)
city.value = location.city
latitude.value = location.latitude
longitude.value = location.longitude
Index.handleResetSearch()
})
const Index = {
/**
* 茶室门店列表
* @param mescroll
*/
upCallback: (mescroll) => {
const userStore = useUserStore()
const userId = userStore.userInfo?.id || 0
const filter = {
page: mescroll.num,
size: mescroll.size,
latitude: latitude.value,
longitude: longitude.value,
search: keywords.value,
user_id: userId
}
uni.showLoading({ title: '加载中...' })
try {
getHomeTeaStoreList(filter).then( res => {
uni.hideLoading()
const curPageData = res.list || [] // 当前页数据
if(mescroll.num == 1) list.value = [] // 第一页需手动制空列表
list.value = list.value.concat(curPageData) //追加新数据
mescroll.endSuccess(curPageData.length, Boolean(res.more))
}).catch(() => {
uni.hideLoading()
mescroll.endErr() // 请求失败, 结束加载
})
} catch (error) {
uni.hideLoading()
}
},
/**
* 初始化首页数据
*/
handleInit: () => {
getHomeBannerList().then(res => {
swiperList.value = res.list.map(item => item.address)
})
},
/**
* 跳转城市选择
*/
handleToCity: () => {
uni.$on('locationUpdate', params => {
console.log("🚀 ~ params:", params)
uni.$off('locationUpdate')
city.value = params.city
latitude.value = params.latitude
longitude.value = params.longitude
Index.handleResetSearch()
})
router.navigateTo(`/pages/city/city?lat=${latitude.value}&lng=${longitude.value}`)
},
/**
* 跳转茶室搜索
*/
handleToSearch: () => {
uni.$on('refreshTeaRoomList', params => {
keywords.value = params.keywords
Index.handleResetSearch()
uni.$off('refreshTeaRoomList')
})
router.navigateTo(`/pages/search/search?keywords=${keywords.value}`)
},
/**
* 跳转到预约茶室页面
*/
handleToReserveRoom: (id: number = 0, type: number = 1) => {
router.navigateTo( `/bundle/tea-room/room?id=${id}&type=${type}`)
},
/**
* 重置搜索
*/
handleResetSearch: () => {
list.value = []
getMescroll().resetUpScroll()
},
/**
* 跳转公众号
*/
handleToWxOfficialAccount: () => {
wx.openOfficialAccountProfile({
username: '', // 此处填写公众号的原始 ID
success: res => {
},
fail: res => {
}
})
},
/**
* 更新定位信息
*/
handleLocationUpdate: (params: any) => {
console.log("🚀 ~ locationUpdate:")
if (
city.value !== params.city ||
latitude.value !== params.latitude ||
longitude.value !== params.longitude
) {
city.value = params.city
latitude.value = params.latitude
longitude.value = params.longitude
Index.handleResetSearch()
}
}
}
</script>
<style lang="scss">
page {
background-color: $cz-page-background;
}
.home-bg {
background-color: $cz-page-background;
background-image: url(#{$OSS}images/home/home_bg.png);
background-size: 100%;
background-repeat: no-repeat;
}
.search-box {
display: flex;
height: 100%;
margin-right: 40px;
--wot-search-padding: 0;
--wot-search-side-padding: 0;
:deep() {
.wd-search {
background: transparent !important;
width: 100% !important;
}
.wd-search__block {
background-color: #fff !important;
}
.wd-search__input {
// #ifdef MP
padding-left: 32px !important;
padding-right: 32px !important;
// #endif
// #ifndef MP
padding-right: 0 !important;
// #endif
}
}
}
.rounded {
border-radius: 20rpx 0rpx 20rpx 0rpx;
}
.ele-center {
left: 50%;
transform: translateX(-50%);
}
</style>