<template> <view style="overflow-y: scroll;"> <!-- 状态栏高度 --> <view :style="{ height: `${statusBarHeight}px` }"></view> <!-- 导航栏 --> <view class="navigationbar" :style="{ height: `${navigationBarHeight}px` }"> <view class="bar-left flex-y-center"> <image src="/static/img/ic-position.png" @tap="chooseLocation()"> </image> <text class="bar-position">{{userAddress}}</text> </view> <view class="bar-center">校园外卖</view> <view style="flex: 1;"> <image @click="goSearch" src="/static/img/ic-search.png"></image> </view> </view> <!-- 主体内容 --> <view class="content" :style="{ marginTop: `${navigationBarHeight + 5 }px` }"> <!-- banner轮播图 --> <view style="margin-top: 10rpx;"> <swiper :indicator-dots="indicatorDots" :autoplay="autoplay" :interval="interval" :duration="duration" circular="true"> <block v-for="(item,index) in bannerList" :key='item.id'> <swiper-item catchtouchmove='catchTouchMove'> <view class="swiper-item"> <image class="banner-img" :src="item.pic" mode="widthFix" /> </view> </swiper-item> </block> </swiper> </view> <!-- 新闻 --> <view class="container"> <!-- 左侧固定图片 --> <image class="left-image" src="/static/img/ic-message.png"></image> <!-- 右侧文字轮播区域 --> <view class="right-text-container"> <swiper :indicator-dots="false" :autoplay="autoplay" interval="2500" :duration="500" vertical="true" circular="true"> <block v-for="(item,index) in messageList" :key='index'> <swiper-item catchtouchmove='catchTouchMove'> <view class='text acea-row row-between-wrapper'> <view class='newsTitle'> {{item.title}} </view> <!-- <view class='newsTitle' v-if="messageList.length = 0"> 暂无 </view> --> </view> </swiper-item> </block> </swiper> <!-- <view class="text-list" :style="{ transform: `translateY(${offset}px)` }"> <view class="text-item" v-for="(item, index) in messageList" :key="index"> {{ item.title }} </view> <view class="text-item" v-if="messageList.length > 0"> {{ messageList[0].title }} </view> </view> --> </view> </view> <!-- 九宫格 --> <view class="content-tab"> <view class="tab-list"> <view class="tab-item flex-col flex-between-center" v-for="(item, index) in cateList" :key="index" @tap="onCateListClick(item)"> <image class="tab-image" :style="{width: !item.isHighLight ? '80rpx' : ''}" :src="item.icon" mode="widthFix"></image> <text :class="item.isHighLight || item.color ? 'tab-text' : 'tab-text2' " :style="{color: item.color || ''}">{{item.name}}</text> </view> </view> </view> <!-- 活动精选 --> <view class="content-goods"> <view> <image src="/static/img/img-hdjx.png" style="width: 298rpx;height: 44rpx;"></image> <text class="goods-more" @tap="goGenDuo">更多 》</text> </view> <view style="display: flex;"> <view class="goods-list" v-for="item in proList" :key="item.id"> <view style="display: flex;" @click="goGoodList(item)"> <view style="margin-right: 20rpx;"> <image :src="item.image" style="width: 134rpx;height: 134rpx;border-radius: 12rpx;"> </image> </view> <view> <view class="goods-title">{{item.name}}</view> <view class="goods-desc">{{item.intro}}</view> <view class="flex-y-center" style="margin-top: 10rpx;"> <image src="/static/img/ic-ykj.png" style="height: 38rpx;width: 86rpx;"></image> <text class="goods-price">¥</text> <text class="goods-price" style="font-size: 30rpx;">{{item.price}}</text> </view> </view> </view> </view> </view> </view> <!-- 销量排行 --> <view class="tab-list" style="margin-top: 10rpx;"> <view :class=" item.checked ? 'tab-item2' : 'tab-item2-false' " v-for="item in labelList" :key="item.id" @click="item2Click(item)">{{item.label}}</view> </view> <view class="content-goods2" v-for="item in merchantList" :key="item.id" @click="merchantTab(item)"> <view> <image :src="item.avatar" style="width: 230rpx;height: 230rpx;"></image> </view> <view style="margin-left: 20rpx;flex: 1;"> <view class=""> <text class="goods-title">{{item.name}}</text> </view> <view style="margin-top: 10rpx;"> <text class="goods-score">{{item.score}}</text> <text class="goods-info" style="margin-left: 10rpx;">月销 {{item.salesVolume}}</text> <text class="goods-info" style="margin-left: 25rpx;">人均 ¥ {{item.perCapita}}</text> </view> <view style="margin-top: 10rpx;display: flex;align-items: center;"> <text class="goods-info">起送 ¥ {{item.perCapita}}</text> <text v-if="!item.isfreeDeliverfee" class="goods-info" style="color: #E5AD21;margin-left: 18rpx;">免配送费</text> <view v-if="!item.isfreeDeliverfee && item.freeDeliverFee > 0" style="color: #999999;font-size: 21rpx;margin-left: 10rpx;text-decoration: line-through;">¥ {{item.freeDeliverFee}}</view> <text v-if="item.isfreeDeliverfee" style="color: #999999;font-size: 21rpx;margin-left: 10rpx;">配送费¥ {{item.distCosts}}</text> <text class="goods-info" style="margin-left: 38rpx;">10分钟</text> <text class="goods-info" style="margin-left: 10rpx;">{{item.distance}}</text> </view> <view style="margin-top: 22rpx;"><text class="goods-sales">已售卖{{item.salesVolume}}件</text></view> <view style="margin-top: 14rpx;"> <text class="goods-labels" v-for="(item2,index2) in item.discountLabel" :key="index2">{{item2}}</text> </view> </view> </view> </view> </view> </template> <script> import QQMapWX from '@/utils/qqmap-wx-jssdk.min.js'; import { getMerchantList, getHomeInfo } from '@/api/home.js'; import { toLogin } from '@/libs/login.js'; import { mapGetters } from "vuex"; import { BACK_URL } from '@/config/cache'; var statusBarHeight = uni.getSystemInfoSync().statusBarHeight + 'px'; let app = getApp(); export default { computed: mapGetters(['isLogin']), data() { return { statusBarHeight: app.globalData.statusBarHeight, navigationBarHeight: 0, userAddress: "定位", indicatorDots: true, autoplay: true, interval: 2000, //切换的间隔时间 duration: 500, //滑动动画时长 bannerList: [], messageList: [], cateList: [], proList: [], labelList: [{ id: 1, label: "销量排行", checked: true }, { id: 2, label: "满减大促", checked: false }, { id: 3, label: "首单立减", checked: false }, { id: 4, label: "减配送费", checked: false }], merchantList: [], currentIndex: 0, offset: 0, } }, //下拉刷新 onPullDownRefresh() { }, onLoad(options) { let that = this; //首页数据加载 // this.getIndexConfig(); // #ifdef MP-WEIXIN // 获取微信胶囊的位置信息 width,height,top,right,left,bottom const custom = wx.getMenuButtonBoundingClientRect() // 导航栏高度(标题栏高度) = 胶囊高度 + (顶部距离 - 状态栏高度) * 2 that.navigationBarHeight = custom.height + (custom.top - that.statusBarHeight) * 2 // console.log("导航栏高度:"+this.globalData.navigationBarHeight) // #endif that.initLocation(); }, methods: { initLocation() { let that = this; this.$util.$L.getLocation().then(res => { const qqmapsdk = new QQMapWX({ key: '7FJBZ-ACWCN-EFWFQ-SBXR5-QXC7K-LPF2U' //key: '7FJBZ-ACWCN-EFWFQ-SBXR5-QXC7K-LPF2U' }); qqmapsdk.reverseGeocoder({ location: { latitude: uni.getStorageSync('user_latitude'), longitude: uni.getStorageSync('user_longitude'), }, success: (res2) => { const address = res2.result.address; // 完整地址(如北京市海淀区中关村) const province = res2.result.ad_info.province; // 省份 const city = res2.result.ad_info.city; // 城市 const recommend = res2.result.address_reference.landmark_l2.title;; // 推荐使用的地址描述,描述精确性较高 console.log('地址信息1:', res2); that.userAddress = recommend; that.getHomeData(); }, fail: (err) => { console.error('逆地理编码失败:', err); } }); }) }, getHomeData() { getHomeInfo({ latitude: uni.getStorageSync('user_latitude'), longitude: uni.getStorageSync('user_longitude'), }).then(res => { this.bannerList = res.data.banner; this.proList = res.data.proList; console.log(this.proList) this.messageList = res.data.headline; this.cateList = res.data.cateList; this.cateList.push({ id: 999, name: '今日吃啥', icon: '/static/img/ic-random.png', color: '#FF9805' }); getMerchantList({ latitude: uni.getStorageSync('user_latitude'), longitude: uni.getStorageSync('user_longitude'), cateId: this.cateList[0].id }).then(res => { this.merchantList = res.data.list; console.log('商品信息:', this.merchantList); }); // this.messageList = [{"id":2,"title":"绿草地活动大促,消费满三十减十五"},{"id":3,"title":"绿草地活动大促,消费满三十减十五33333"}]; console.log("this.messageList--", this.messageList) // this.startScroll(); }) }, item2Click(item) { item.checked = !item.checked; }, startScroll() { setInterval(() => { this.currentIndex = (this.currentIndex + 1) % this.messageList.length; this.offset = -this.currentIndex * 20; // 20px 是单行高度 }, 2000); // 2秒切换一次 }, goSearch() { this.$util.navigateTo('/pages/goods/goods_search/index'); }, goGenDuo() { this.$util.navigateTo(`/pages/goods/goods_list/index?cateId=${this.cateList[0].id}`); }, //配送时间转换 convertMinutes(minutes) { const mins = Number(minutes); if (isNaN(mins)) return '无效输入'; if (mins > 60) { const hours = Math.floor(mins / 60); const remaining = mins % 60; let result = []; if (hours > 0) result.push(`${hours}小时`); if (remaining > 0) result.push(`${remaining}分钟`); return result.join('') || '0分钟'; } else { return `${mins}分钟`; } }, merchantTab(item) { let cid = item.cid // 修改跳转 uni.navigateTo({ url: `/pages/merchant/home/index?merId=${item.id}` // url: `/pages/goods_cate/index?id=${item.id}` }) }, onCateListClick(item) { if (!this.isLogin) { this.openAuto(); } else { if (item.link) { uni.navigateTo({ url: item.link + `?id=${item.id}&navTitle=${item.name}` }) } } }, goGoodList(item) { uni.navigateTo({ url: `/pages/goods/goods_details/index?id=${item.productId}&mt=0&iSshop=1` }) }, //选择定位 chooseLocation: function() { this.$util.$L.getLocation().then(res => { uni.chooseLocation({ latitude: uni.getStorageSync('user_latitude'), longitude: uni.getStorageSync('user_longitude'), success: (res) => { this.userAddress = res.name; getMerchantList({ latitude: res.latitude, longitude: res.longitude, cateId: this.cateList[0].id }).then(data => { this.merchantList = data.data.list; console.log('商品信息:', this.merchantList); }); // this.$set(this.userAddress, 'detail', res.name); } }) }) }, // 打开授权 openAuto() { Cache.set(BACK_URL, '') toLogin(); }, }, } </script> <style> page { height: auto; display: flex; flex-direction: column; height: 100%; /* #ifdef H5 */ background-color: #fff; /* #endif */ } </style> <style lang="scss" scoped> .navigationbar { display: flex; background-color: #FF6702; color: #fff; align-items: center; position: fixed; z-index: 100; width: 100%; } .navigationbar image { width: 35rpx; height: 35rpx; vertical-align: middle; } .bar-left { flex: 1; margin-left: 40rpx; } .bar-position { margin-left: 16rpx; font-size: 22rpx; overflow: hidden; /*超出部分隐藏*/ white-space: nowrap; /*禁止换行*/ text-overflow: ellipsis; /*省略号*/ } .bar-center { flex: 1; font-size: 36rpx; } .swiper-item { flex-direction: column; justify-content: center; align-items: center; background-color: #999; color: #fff; text-align: center; width: 712rpx; height: 230rpx; border-radius: 10rpx; margin: 0 auto; } .banner-img { width: 712rpx; height: 230rpx; border-radius: 10rpx; } .content { margin: 0 20rpx; } .content-message { background-color: #fff; margin-top: 10rpx; padding: 10rpx; } .content-message image { width: 38rpx; height: 38rpx; vertical-align: middle; } .content-message text { font-size: 23rpx; color: #646464; margin-left: 16rpx; } .content-tab { background: linear-gradient(225deg, #ECF3FE 0%, #FEFEFE 100%); border-radius: 23rpx; padding: 20rpx; } .tab-list { display: flex; /* 启用弹性布局 */ flex-direction: row; /* 横向排列 */ justify-content: space-between; /* 均匀分布子项 */ flex-wrap: wrap; /* 允许换行(适用于屏幕宽度不足时) */ } .tab-item { width: 18%; /* 5个元素平分宽度,留1%作为间隙 */ margin-bottom: 20rpx; /* 底部间距 */ text-align: center; /* 内容居中 */ color: #141414; font-size: 24rpx; } .tab-image { width: 100%; /* 宽度占满父容器 */ height: 80rpx; /* 固定图片高度 */ border-radius: 10rpx; /* 圆角效果 */ background-color: #f5f5f5; /* 占位背景色 */ } .tab-text { display: block; font-size: 27rpx; font-weight: 600; color: #141414; margin-top: 10rpx; } .tab-text2 { display: block; font-size: 23rpx; font-weight: 400; color: #141414; margin-top: 10rpx; } .content-goods { background: #FFFFFF; border-radius: 23rpx; padding: 20rpx; margin-top: 10rpx; } .tab-item2 { width: 23%; /* 5个元素平分宽度,留2%作为间隙 */ text-align: center; background-color: #FFC127; border-radius: 8rpx; font-size: 23rpx; padding: 6rpx; font-weight: 400; } .tab-item2-false { width: 23%; /* 5个元素平分宽度,留2%作为间隙 */ text-align: center; background-color: #fff; border-radius: 8rpx; font-size: 23rpx; padding: 6rpx; font-weight: 400; } .content-goods2 { background: #FFFFFF; border-radius: 23rpx; margin-top: 10rpx; padding: 20rpx; display: flex; } .goods-more { font-size: 21rpx; color: #999999; float: right; line-height: 44rpx; } .goods-list { flex: 1; margin-right: 18rpx; } .goods-title { color: #141414; font-size: 26rpx; font-weight: 600; } .goods-desc { color: #646464; font-size: 21rpx; margin-top: 10rpx; } .goods-price { color: #FF9805; font-size: 34rpx; font-weight: 600; } .goods-score { color: #FD6716; font-size: 26rpx; } .goods-info { color: #999999; font-size: 21rpx; } .goods-info3 { color: #999999; font-size: 21rpx; margin-left: 10rpx; text-decoration: line-through; } .goods-sales { background-color: #FEEFE5; color: #FF6702; border-radius: 8rpx; font-size: 21rpx; padding: 4rpx 20rpx; } .goods-labels { background-color: #FFF6F6; color: #FF4B4B; border: 2rpx solid #FF4B4B; border-radius: 8rpx; font-size: 21rpx; padding: 4rpx 16rpx; margin-right: 20rpx; } .container { display: flex; align-items: center; padding: 12rpx; background: #ffffff; margin: 10rpx 0; } .left-image { width: 38rpx; height: 38rpx; margin-left: 20rpx; margin-right: 16rpx; } .right-text-container { flex: 1; height: 20px; /* 单行文字高度 */ overflow: hidden; position: relative; } .text-list { position: absolute; width: 100%; transition: transform 0.5s ease; /* 动画过渡 */ } .text-item { height: 40rpx; line-height: 40rpx; font-size: 23rpx; color: #646464; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .newsTitle { font-size: 23rpx; color: #646464; margin-top: 2rpx; } </style>