Files
Smart-Farm/uniapp/uni-app/pages/home.vue
2026-01-07 10:16:49 +08:00

732 lines
16 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.
<template>
<view class="pages-home" v-if="isLoad">
<uni-nav-bar :fixed="true" title="智慧农场"></uni-nav-bar>
<view :style="{ height: `${configInfo.navBarHeight}px` }"></view>
<view class="banner-wrap">
<image class="banner" mode="aspectFill" src="@/static/image/imgicon/banner.png"></image>
<view class="banner-info">
<view class="day-info">
<image class="icon" mode="aspectFit" src="@/static/image/imgicon/weather_icon1.png"></image>
<view class="content">28°~32°</view>
</view>
<view class="address">深圳市·龙岗区·阿花画画啊啊啊啊啊啊啊啊地</view>
<view class="row-card">
<view class="row-box">
<view class="icon">
<image style="width: 22rpx; height: 22rpx" mode="aspectFit" src="@/static/image/imgicon/weather1.png"></image>
</view>
<view class="label">pm25值</view>
<view>32</view>
</view>
<view class="row-box">
<view class="icon">
<image style="width: 16rpx; height: 14rpx" mode="aspectFit" src="@/static/image/imgicon/weather2.png"></image>
</view>
<view class="label">风力</view>
<view></view>
</view>
<view class="row-box">
<view class="icon">
<image style="width: 16rpx; height: 20rpx" mode="aspectFit" src="@/static/image/imgicon/weather3.png"></image>
</view>
<view class="label">湿度</view>
<view>90%</view>
</view>
</view>
</view>
<view class="banner-tool">
<image class="tool-but" mode="aspectFill" src="@/static/image/imgicon/soso.png"></image>
<image class="tool-but" mode="aspectFill" src="@/static/image/imgicon/qrcode.png"></image>
</view>
</view>
<view class="menu-card">
<view class="menu-item">
<image class="back" mode="aspectFit" src="@/static/image/imgicon/menu1.png"></image>
<view class="name">租地种菜</view>
</view>
<view class="menu-item">
<image class="back" mode="aspectFit" src="@/static/image/imgicon/menu2.png"></image>
<view class="name">认种认养</view>
</view>
<view class="menu-item">
<image class="back" mode="aspectFit" src="@/static/image/imgicon/menu3.png"></image>
<view class="name">监控直播</view>
</view>
<view class="menu-item">
<image class="back" mode="aspectFit" src="@/static/image/imgicon/menu4.png"></image>
<view class="name">农场集市</view>
</view>
</view>
<view class="title-wrap">
<view class="title">农场秀</view>
<view class="more">更多</view>
</view>
<scroll-view class="video-scroll" scroll-x enable-flex>
<view class="video-list-box">
<view class="video-item" v-for="i in 9">
<image class="video-img" mode="aspectFill" src="@/static/image/imgicon/banner.png"></image>
<image class="video-star" mode="aspectFill" src="@/static/image/imgicon/video.png"></image>
<view class="content">
<image class="avatar" mode="aspectFill" src="@/static/image/imgicon/banner.png"></image>
<view class="name">喜羊羊</view>
<image class="count-img" mode="aspectFit" src="@/static/image/imgicon/zan.png"></image>
<view class="count">189</view>
</view>
</view>
</view>
</scroll-view>
<view class="title-wrap">
<view class="title">必玩攻略</view>
<view class="more">更多</view>
</view>
<view class="list-wrap">
<view class="list-item" v-for="i in 5">
<image class="img" mode="aspectFill" src="@/static/image/imgicon/banner.png"></image>
<view class="content">
<view class="name">必玩攻略必玩攻略必玩攻略必玩攻略必玩攻略必玩攻略必玩攻略必玩攻略必玩攻略必玩攻略</view>
<view class="money-wrap">
<view class="money">
<text class="unit"></text>
300.00
</view>
<view class="count-but"></view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { mapState, mapActions, mapMutations } from 'vuex';
import uniSegmentedControl from '@/components/uni-segmented-control.vue';
export default {
components: {
uniSegmentedControl
},
data() {
return {
scrollTop: 0,
options: {},
weather_img: `https://mat1.gtimg.com/pingjs/ext2020/weather/pc/icon/currentweather/`,
menuList: [
{
id: 1,
title: '土地租赁',
img_name: 'land',
url: '/pages/land'
},
{
id: 2,
title: '农业认养',
img_name: 'claim',
url: '/pages/claim'
},
{
id: 3,
title: '视频监控',
img_name: 'monitor',
url: '/home/pages/monitor/list'
},
{
id: 4,
title: '农场商城',
img_name: 'shop',
url: '/pages/shop'
},
{
id: 5,
title: '会员充值',
img_name: 'stored',
url: '/mine/pages/balance/list'
},
{
id: 6,
title: '众筹认养',
img_name: 'collage',
url: '/claim/pages/collage/list'
},
{
id: 7,
title: '限时秒杀',
img_name: 'seckill',
url: '/shop/pages/seckill'
},
{
id: 8,
title: '积分商城',
img_name: 'integral',
url: '/shop/pages/integral/list'
},
{
id: 9,
title: '农场签到',
img_name: 'sign',
url: '/shop/pages/sign'
},
{
id: 10,
title: '积分抽奖',
img_name: 'luck',
url: '/shop/pages/luck'
}
],
isLoad: true,
loading: true,
detail: {},
about_us: 0,
weather: {},
store_list: [],
today: '',
cur_time: '',
time_key: 'day'
};
},
computed: mapState({
primaryColor: (state) => state.config.configInfo.primaryColor,
subColor: (state) => state.config.configInfo.subColor,
configInfo: (state) => state.config.configInfo,
userInfo: (state) => state.user.userInfo,
location: (state) => state.user.location,
loginType: (state) => state.user.loginType
}),
async onLoad() {
console.log('====onload');
if (this.isLoad) return;
this.initIndex();
},
async onShow() {
let cur_time = this.$util.DateToUnix(this.$util.formatTime(new Date(), 'YY-M-D h:m:s'));
let time = this.$util.DateToUnix(this.$util.formatTime(new Date(), 'YY-M-D'));
let min = time + 8 * 3600 - 1;
let max = time + 19 * 3600 + 1;
this.time_key = cur_time > min && cur_time < max ? 'day' : 'night';
if (!this.isLoad || this.location.lat) return;
let [err, result] = await uni.getSetting();
if (err || !result.authSetting[`scope.userLocation`]) return;
this.initIndex();
},
onPageScroll(e) {
this.scrollTop = e.scrollTop;
},
onPullDownRefresh() {
// #ifndef APP-PLUS
uni.showNavigationBarLoading();
// #endif
this.initRefresh();
uni.stopPullDownRefresh();
},
onShareAppMessage(e) {
let { id: pid } = this.userInfo;
let path = `/pages/home?pid=${pid}`;
this.$util.log(path);
return {
title: '',
imageUrl: '',
path
};
},
methods: {
...mapActions(['getConfigInfo']),
...mapMutations(['updateUserItem']),
async initIndex(refresh = false) {
this.cur_time = this.$util.formatTime(new Date(), 'YY-M-D');
this.today = this.$util.formatTime(new Date(), 'YY年M月D日');
if (!this.configInfo.id || refresh) {
await this.getConfigInfo();
if (this.loginType == 'apple') {
this.updateUserItem({
key: 'isShowLogin',
val: false
});
}
}
await this.getLocation();
if (!refresh) {
this.$util.showLoading();
}
let { lat = 0, lng = 0 } = this.location;
let [detail, coupon] = await Promise.all([
this.$api.home.index({
lat,
lng
}),
this.$api.shop.couponList()
]);
detail.coupon_total = coupon.total;
let { status = 0, data } = detail.weather;
if (status == 200) {
let { forecast_24h } = data;
let cur_day = forecast_24h.filter((item) => {
return item.time == this.cur_time;
});
data.forecast_24h = cur_day.length > 0 ? cur_day[0] : [];
detail.weather = data;
}
this.detail = detail;
this.isLoad = true;
this.loading = false;
this.$util.hideAll();
},
initRefresh() {
this.initIndex(true);
},
async getLocation() {
let { location } = this;
if (!location.lat) {
try {
// #ifdef H5
// H5环境下先检查缓存的位置信息
let cachedLocation = uni.getStorageSync('cached_location');
let cacheTime = uni.getStorageSync('location_cache_time');
let now = new Date().getTime();
// 如果有缓存且缓存时间不超过30分钟直接使用缓存的位置
if (cachedLocation && cacheTime && now - cacheTime < 30 * 60 * 1000) {
location = cachedLocation;
} else {
// 没有缓存或缓存过期,才获取新位置
location = await this.$util.getBmapLocation();
}
// #endif
// #ifndef H5
// 非H5环境直接获取位置
location = await this.$util.getBmapLocation();
// #endif
this.updateUserItem({
key: 'location',
val: location
});
} catch (error) {
console.log('获取位置失败:', error);
// 获取位置失败时不更新location使用默认值
this.$util.showToast({
title: '获取位置失败,使用默认位置'
});
}
}
},
// 选择地区
async toChooseLocation(e) {
await this.$util.checkAuth({
type: 'userLocation'
});
let [, { address = '', longitude: lng = 0, latitude: lat = 0 } = {}] = await uni.chooseLocation();
if (!lng) return;
let location = {
lng,
lat,
address
};
this.updateUserItem({
key: 'location',
val: location
});
this.initRefresh();
},
toMenu(index) {
let { title, url } = this.menuList[index];
let arr = ['土地租赁', '农业认养'];
let openType = arr.includes(title) ? 'switchTab' : title == '农场商城' ? 'reLaunch' : 'navigateTo';
this.$util.toCheckLogin({
url,
openType
});
},
// 轮播图/广告图跳转
goBanner(e) {
// connect_type 1店铺2文章3图片4店铺
let { connect_type, text_id: id = 0, img: current } = e.item;
switch (connect_type) {
case 1:
case 2:
case 4:
let page = {
1: `/home/pages/farm/detail?id=${id}`,
2: `/home/pages/article?id=${id}&type=1`,
4: `/shop/pages/store?id=${id}`
};
let url = page[connect_type];
this.$util.toCheckLogin({
url
});
break;
case 3:
this.$util.previewImage({
current,
urls: [current]
});
break;
}
},
goAbout() {
if (!this.detail.about_us) return;
this.$util.toCheckLogin({
url: `/home/pages/about`
});
},
// 商品/店铺/公益栏目详情
async goDetail(type, key, index) {
let { id } = this.detail[key][index];
let url = '';
switch (type) {
case 1:
url = `/shop/pages/detail?id=${id}`;
break;
case 2:
url = `/shop/pages/store?id=${id}`;
break;
case 3:
url = `/home/pages/article?id=${id}&type=2`;
break;
}
this.$util.toCheckLogin({
url
});
}
}
};
</script>
<style lang="scss">
.pages-home{
min-height: 100vh;
background: #ffffff;
}
.banner-wrap {
position: relative;
.banner {
width: 100%;
height: 445rpx;
display: block;
}
.banner-info {
position: absolute;
left: 28rpx;
top: 0;
background: rgba(0, 0, 0, 0.1);
width: 230rpx;
padding: 15rpx 0;
border-radius: 0 0 4rpx 4rpx;
.day-info {
display: flex;
padding: 0 8rpx;
align-items: center;
.icon {
width: 58rpx;
height: 58rpx;
}
.content {
font-family: PingFang SC;
font-weight: 600;
color: #41beff;
font-size: 33rpx;
text-shadow: 0 3rpx 6rpx rgba(0, 0, 0, 0.16);
}
}
.address {
font-weight: 600;
color: #ffffff;
font-size: 20rpx;
line-height: 28rpx;
margin: 0 14rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.row-card {
margin: 10rpx 10rpx 0;
padding-top: 10rpx;
font-weight: 600;
color: #ffffff;
font-size: 20rpx;
line-height: 28rpx;
position: relative;
&::after {
content: ' ';
display: block;
border-top: 1px solid #ffffff;
width: 200%;
height: 0;
position: absolute;
left: 0;
top: 0;
transform: scale(0.5);
transform-origin: 0 0;
}
.row-box {
display: flex;
align-items: center;
& + .row-box {
margin-top: 10rpx;
}
.icon {
width: 22rpx;
height: 22rpx;
margin-right: 10rpx;
display: flex;
align-items: center;
justify-content: center;
}
.label {
flex: 1;
}
}
}
}
.banner-tool {
position: absolute;
top: 25rpx;
right: 28rpx;
.tool-but {
width: 50rpx;
height: 50rpx;
display: block;
& + .tool-but {
margin-top: 20rpx;
}
}
}
}
.menu-card {
position: relative;
z-index: 1;
margin: -90rpx 28rpx 0;
background: #ffffff;
border-radius: 20rpx;
display: flex;
justify-content: space-evenly;
box-shadow: 0 3rpx 7rpx rgba(0, 0, 0, 0.14);
padding: 40rpx 0 26rpx;
.menu-item {
position: relative;
.back {
width: 140rpx;
height: 140rpx;
display: block;
margin: 0 auto;
}
.name {
position: absolute;
bottom: 25rpx;
left: 0;
width: 100%;
text-align: center;
line-height: 28rpx;
color: #ffffff;
font-size: 22rpx;
}
}
}
.title-wrap {
display: flex;
align-items: center;
justify-content: space-between;
margin: 38rpx 34rpx 10rpx;
.title {
font-weight: 500;
font-size: 32rpx;
line-height: 44rpx;
color: #2b2b2b;
}
.more {
font-size: 24rpx;
color: #4f4f4f;
}
}
.video-scroll {
overflow: auto;
display: flex;
height: 366rpx;
}
.video-list-box {
display: flex;
padding: 0 28rpx;
height: 360rpx;
.video-item {
height: 360rpx;
width: 258rpx;
flex-shrink: 0;
background: #ffffff;
position: relative;
border-radius: 15rpx;
overflow: hidden;
box-shadow: 0 3rpx 6rpx rgba(0, 0, 0, 0.16);
& + .video-item {
margin-left: 17rpx;
}
.video-img {
height: 300rpx;
width: 100%;
display: block;
}
.video-star {
position: absolute;
height: 300rpx;
width: 100%;
top: 0;
left: 0;
z-index: 1;
}
.content {
height: 60rpx;
display: flex;
align-items: center;
padding: 0 8rpx;
.avatar {
width: 28rpx;
height: 28rpx;
margin-right: 10rpx;
border-radius: 50%;
}
.name {
font-size: 22rpx;
color: #2b2b2b;
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.count-img {
margin: 0 4rpx;
width: 18rpx;
height: 16rpx;
}
.count {
font-size: 20rpx;
color: #2b2b2b;
}
}
}
}
.list-wrap {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
padding: 0 28rpx 200rpx;
.list-item {
width: 340rpx;
background: #ffffff;
position: relative;
border-radius: 15rpx;
overflow: hidden;
box-shadow: 0 3rpx 10rpx rgba(0, 0, 0, 0.16);
margin-bottom: 20rpx;
.img {
display: block;
width: 100%;
height: 340rpx;
}
.content {
padding: 18rpx 12rpx 10rpx;
.name {
font-weight: bold;
color: #2b2b2b;
font-size: 24rpx;
line-height: 33rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.money-wrap{
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 10rpx;
.money{
font-weight: bold;
font-size: 32rpx;
line-height: 46rpx;
color: #FF0000;
}
.unit{
font-size: 24rpx;
}
}
}
}
}
.count-but{
position: relative;
background:linear-gradient(to bottom, #43C5FE, #358FFD);
width: 42rpx;
height: 42rpx;
border-radius: 50%;
&::after{
content: " ";
display: block;
background: #ffffff;
width: 24rpx;
height: 4rpx;
border-radius: 4rpx;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
&::before{
content: " ";
display: block;
background: #ffffff;
width: 4rpx;
height: 24rpx;
border-radius: 4rpx;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
</style>