Sprinkler-app/pages/nearbystores/index.vue
2025-12-26 16:53:58 +08:00

751 lines
22 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="page">
<view class="header">
<view class="nav">
<view :class="['nav-item', currentTab === 0 ? 'active' : '']" @tap="switchTab(0)">关注</view>
<view :class="['nav-item', currentTab === 1 ? 'active' : '']" @tap="switchTab(1)">推荐</view>
<view :class="['nav-item', currentTab === 2 ? 'active' : '']" @tap="switchTab(2)">附近</view>
</view>
<view class="search-box">
<view class="search-input">
<image src="https://api.ccttiot.com/smartmeter/img/static/upZuHOsydQDHm4LqYqxx" mode=""></image>
<input type="text" v-model="keyword" placeholder="输入感兴趣的话题" @confirm="onSearch"/>
</view>
<view class="search-btn" @click="btnadd"> <image src="https://api.ccttiot.com/78IrdVCE6prvcbafd546d77b7e0624881c4c3f809b50.png" mode=""></image> </view>
</view>
</view>
<swiper class="feed-swiper" :current="currentTab" :circular="false" duration="300" @change="onSwiperChange">
<swiper-item>
<scroll-view class="feed" @scrolltolower="handqixing" scroll-y refresher-enabled @refresherrefresh="onRefresh" :refresher-triggered="isRefreshing" refresher-default-style="black">
<view class="waterfall-container">
<view class="waterfall-left">
<view class="demo-warter" v-for="(item, index) in feedLists.filter((_, i) => i % 2 === 0)" :key="index" @click="btngonglue(item)">
<u-lazy-load
v-if="!isVideo(firstMedia(item))"
threshold="-450"
border-radius="0"
:image="firstMedia(item)"
:index="index"
></u-lazy-load>
<view v-else class="video-holder">
<video
class="feed-video"
:src="firstMedia(item)"
:poster="item.cover || firstMedia(item)"
autoplay
controls
playsinline
webkit-playsinline
muted
></video>
</view>
<view class="dizhi">
{{item.title && item.title.length > 10 ? item.title.slice(0,20) + '...' : item.title}}
</view>
<view class="cont">
<view class="lt">
<image :src="item.userAvatar" mode="aspectFill"></image>
{{item.nickName && item.nickName.length > 4 ? item.nickName.slice(0,20) + '...' : item.nickName}}
</view>
<view class="rt">
<image v-if="item.isLiked == true" src="https://api.ccttiot.com/smartmeter/img/static/uCxUJSEQTStvqaf93xox" mode=""></image>
<image v-else src="https://api.ccttiot.com/smartmeter/img/static/uypbgeMkBQw7XWmzKmm6" mode=""></image>
{{ item.likes }}
</view>
</view>
</view>
</view>
<view class="waterfall-right">
<view class="demo-warter" v-for="(item, index) in feedLists.filter((_, i) => i % 2 === 1)" :key="index" @click="btngonglue(item)">
<u-lazy-load
v-if="!isVideo(firstMedia(item))"
threshold="-450"
border-radius="0"
:image="firstMedia(item)"
:index="index"
></u-lazy-load>
<view v-else class="video-holder">
<video
class="feed-video"
:src="firstMedia(item)"
:poster="item.cover || firstMedia(item)"
autoplay
controls
playsinline
webkit-playsinline
muted
></video>
</view>
<view class="dizhi">
{{item.title && item.title.length > 10 ? item.title.slice(0,20) + '...' : item.title}}
</view>
<view class="cont">
<view class="lt">
<image :src="item.userAvatar" mode="aspectFill"></image>
{{item.nickName && item.nickName.length > 4 ? item.nickName.slice(0,20) + '...' : item.nickName}}
</view>
<view class="rt">
<image v-if="item.isLiked == true" src="https://api.ccttiot.com/smartmeter/img/static/uCxUJSEQTStvqaf93xox" mode=""></image>
<image v-else src="https://api.ccttiot.com/smartmeter/img/static/uypbgeMkBQw7XWmzKmm6" mode=""></image>
{{ item.likes }}
</view>
</view>
</view>
</view>
</view>
<view class="" style="width: 100%;text-align: center;margin-top: 30rpx;color: #ccc;">
当前没有更多关注动态咯...
</view>
</scroll-view>
</swiper-item>
<swiper-item>
<scroll-view class="feed" @scrolltolower="handqixing" scroll-y refresher-enabled @refresherrefresh="onRefresh" :refresher-triggered="isRefreshing" refresher-default-style="black">
<view class="waterfall-container">
<view class="waterfall-left">
<view class="demo-warter" v-for="(item, index) in feedList.filter((_, i) => i % 2 === 0)" :key="index" @click="btngonglue(item)">
<u-lazy-load
v-if="!isVideo(firstMedia(item))"
threshold="-450"
border-radius="0"
:image="firstMedia(item)"
:index="index"
></u-lazy-load>
<view v-else class="video-holder">
<video
class="feed-video"
:src="firstMedia(item)"
:poster="item.cover || firstMedia(item)"
autoplay
controls
playsinline
webkit-playsinline
muted
></video>
</view>
<view class="dizhi">
{{item.title && item.title.length > 10 ? item.title.slice(0,20) + '...' : item.title}}
</view>
<view class="cont">
<view class="lt">
<image :src="item.userAvatar" mode="aspectFill"></image>
{{item.nickName && item.nickName.length > 4 ? item.nickName.slice(0,20) + '...' : item.nickName}}
</view>
<view class="rt">
<image v-if="item.isLiked == true" src="https://api.ccttiot.com/smartmeter/img/static/uCxUJSEQTStvqaf93xox" mode=""></image>
<image v-else src="https://api.ccttiot.com/smartmeter/img/static/uypbgeMkBQw7XWmzKmm6" mode=""></image>
{{ item.likes }}
</view>
</view>
</view>
</view>
<view class="waterfall-right">
<view class="demo-warter" v-for="(item, index) in feedList.filter((_, i) => i % 2 === 1)" :key="index" @click="btngonglue(item)">
<u-lazy-load
v-if="!isVideo(firstMedia(item))"
threshold="-450"
border-radius="0"
:image="firstMedia(item)"
:index="index"
></u-lazy-load>
<view v-else class="video-holder">
<video
class="feed-video"
:src="firstMedia(item)"
:poster="item.cover || firstMedia(item)"
autoplay
controls
playsinline
webkit-playsinline
muted
></video>
</view>
<view class="dizhi">
{{item.title && item.title.length > 10 ? item.title.slice(0,20) + '...' : item.title}}
</view>
<view class="cont">
<view class="lt">
<image :src="item.userAvatar" mode="aspectFill"></image>
{{item.nickName && item.nickName.length > 4 ? item.nickName.slice(0,20) + '...' : item.nickName}}
</view>
<view class="rt">
<image v-if="item.isLiked == true" src="https://api.ccttiot.com/smartmeter/img/static/uCxUJSEQTStvqaf93xox" mode=""></image>
<image v-else src="https://api.ccttiot.com/smartmeter/img/static/uypbgeMkBQw7XWmzKmm6" mode=""></image>
{{ item.likes }}
</view>
</view>
</view>
</view>
</view>
<view class="" style="width: 100%;text-align: center;margin-top: 30rpx;color: #ccc;">
当前没有更多推荐动态咯...
</view>
</scroll-view>
</swiper-item>
<swiper-item>
<scroll-view class="feed" @scrolltolower="handqixing" scroll-y refresher-enabled @refresherrefresh="onRefresh" :refresher-triggered="isRefreshing" refresher-default-style="black">
<view class="waterfall-container">
<view class="waterfall-left">
<view class="demo-warter" v-for="(item, index) in feedList.filter((_, i) => i % 2 === 0)" :key="index" @click="btngonglue(item)">
<u-lazy-load
v-if="!isVideo(firstMedia(item))"
threshold="-450"
border-radius="0"
:image="firstMedia(item)"
:index="index"
></u-lazy-load>
<view v-else class="video-holder">
<video
class="feed-video"
:src="firstMedia(item)"
:poster="item.cover || firstMedia(item)"
autoplay
controls
playsinline
webkit-playsinline
muted
></video>
</view>
<view class="dizhi">
{{item.title && item.title.length > 10 ? item.title.slice(0,20) + '...' : item.title}}
</view>
<view class="cont">
<view class="lt">
<image :src="item.userAvatar" mode="aspectFill"></image>
{{item.nickName && item.nickName.length > 4 ? item.nickName.slice(0,20) + '...' : item.nickName}}
</view>
<view class="rt">
<image v-if="item.isLiked == true" src="https://api.ccttiot.com/smartmeter/img/static/uCxUJSEQTStvqaf93xox" mode=""></image>
<image v-else src="https://api.ccttiot.com/smartmeter/img/static/uypbgeMkBQw7XWmzKmm6" mode=""></image>
{{ item.likes }}
</view>
</view>
</view>
</view>
<view class="waterfall-right">
<view class="demo-warter" v-for="(item, index) in feedList.filter((_, i) => i % 2 === 1)" :key="index" @click="btngonglue(item)">
<u-lazy-load
v-if="!isVideo(firstMedia(item))"
threshold="-450"
border-radius="0"
:image="firstMedia(item)"
:index="index"
></u-lazy-load>
<view v-else class="video-holder">
<video
class="feed-video"
:src="firstMedia(item)"
:poster="item.cover || firstMedia(item)"
autoplay
controls
playsinline
webkit-playsinline
muted
></video>
</view>
<view class="dizhi">
{{item.title && item.title.length > 10 ? item.title.slice(0,20) + '...' : item.title}}
</view>
<view class="cont">
<view class="lt">
<image :src="item.userAvatar" mode="aspectFill"></image>
{{item.nickName && item.nickName.length > 4 ? item.nickName.slice(0,20) + '...' : item.nickName}}
</view>
<view class="rt">
<image v-if="item.isLiked == true" src="https://api.ccttiot.com/smartmeter/img/static/uCxUJSEQTStvqaf93xox" mode=""></image>
<image v-else src="https://api.ccttiot.com/smartmeter/img/static/uypbgeMkBQw7XWmzKmm6" mode=""></image>
{{ item.likes }}
</view>
</view>
</view>
</view>
</view>
<view class="" style="width: 100%;text-align: center;margin-top: 30rpx;color: #ccc;">
当前没有更多推荐动态咯...
</view>
</scroll-view>
</swiper-item>
</swiper>
<tab-bar :indexs='11'></tab-bar>
</view>
</template>
<script>
export default {
data() {
return {
currentTab: 1,
feedList: [],//推荐
feedLists: [],//关注
flowList:[],//附近
isRefreshing:false,
isLoading: false,
total:0,
pageNum:1,
keyword:'',
hasUnreadMessage:false,
userId:'',
currLat:'',
currLon:''
}
},
onLoad() {
this.getdongtailist()
uni.getLocation({
type: 'gcj02',
success: (res) => {
},
fail: (err) => {
console.error('获取位置失败:', err)
}
})
},
onShow() {
this.getinfo()
},
// 分享到好友(会话)
onShareAppMessage: function() {
return {
title: '绿小能',
path: '/pages/index/index'
}
},
// 分享到朋友圈
onShareTimeline: function() {
return {
title: '绿小能',
query: '',
path: '/pages/index/index'
}
},
methods: {
// 点击跳转到动态详情
btngonglue(item){
uni.navigateTo({
url:'/page_user/dongtai/dongtaixq?id=' + item.id
})
},
// 点击跳转发布动态
btnadd(){
uni.navigateTo({
url:'/page_user/dongtai/index'
})
},
// 请求我的个人信息
getinfo(){
this.$u.get(`/system/user/profile`).then(res =>{
if(res.code == 200){
this.userId = res.data.userId
uni.setStorageSync('user',res.data)
uni.setStorageSync('userId',this.userId) //将自己的用户ID存到本地
console.log(this.userId);
}
})
},
// 判断获取的数据是否为视频(通过后缀名)
isVideo(url) {
if (!url || typeof url !== 'string') return false
const lower = url.split('?')[0].toLowerCase()
return ['.mp4','.mov','.m4v','.mkv','.avi','.wmv','.flv','.webm','.3gp'].some(ext => lower.endsWith(ext))
},
firstMedia(item) {
if (!item || !item.picture) return ''
if (Array.isArray(item.picture)) {
return item.picture[0] || ''
}
return item.picture.split(',')
.map(url => url.trim())
.find(url => !!url) || ''
},
// 请求推荐动态列表
getdongtailist(){
this.$u.get(`/app/feed/list?pageNum=${this.pageNum}&pageSize=20&keyword=${this.keyword}&currLon=${this.currLon}&currLat=${this.currLat}`).then(res =>{
if(res.code == 200){
this.total = res.total
if(this.pageNum == 1){
this.pageNum++
this.feedList = res.rows
}else{
this.pageNum++
this.feedList = this.feedList.concat(res.rows)
}
}
})
},
// 请求关注动态列表
getguanzhulist(){
this.$u.get(`/app/feed/followed?pageNum=${this.pageNum}&pageSize=20&keyword=${this.keyword}`).then(res =>{
if(res.code == 200){
this.total = res.total
if(this.pageNum == 1){
this.pageNum++
this.feedLists = res.rows
}else{
this.pageNum++
this.feedLists = this.feedLists.concat(res.rows)
}
}
})
},
// 点击消息跳转到详情页 、右右左左右
btnxq(index){
if(this.currentTab == 1){ //推荐 feedList
uni.navigateTo({
url:'/page_fenbao/guangchang/dongtaixq?id=' + this.feedList[index].id
})
}else if(this.currentTab == 0){ //关注 feedLists
uni.navigateTo({
url:'/page_fenbao/guangchang/dongtaixq?id=' + this.feedLists[index].id
})
}else{ //附近
console.log('附近');
uni.navigateTo({
url:'/page_fenbao/guangchang/dongtaixq?id=' + this.feedList[index].id
})
}
},
// 头部tab点击切换
switchTab(index) {
this.currentTab = index
this.pageNum = 1
},
// 点击搜索指定的消息
onSearch() {
this.pageNum = 1
if(this.currentTab == 1){
this.currLat = ''
this.currLon = ''
this.getdongtailist()
}else if(this.currentTab == 0){
this.getguanzhulist()
}else{
uni.getLocation({
type: 'gcj02',
success: (res) => {
this.currLat = res.latitude
this.currLon = res.longitude
this.getdongtailist()
},
fail: (err) => {
console.error('获取位置失败:', err)
}
})
}
},
// 轮播图左右滑动切换事件
onSwiperChange(e) {
this.currentTab = e.detail.current
this.pageNum = 1
if(e.detail.current == 1){
this.currLat = ''
this.currLon = ''
this.getdongtailist()
}else if(e.detail.current == 0){
this.getguanzhulist()
}else{
console.log('附近');
uni.getLocation({
type: 'gcj02',
success: (res) => {
this.currLat = res.latitude
this.currLon = res.longitude
this.getdongtailist()
},
fail: (err) => {
console.error('获取位置失败:', err)
}
})
}
},
// 上拉加载更多数据
handqixing() {
if(this.currentTab == 1){
if(this.feedList.length < this.total){
this.currLat = ''
this.currLon = ''
this.getdongtailist()
}
}else if(this.currentTab == 0){
if(this.feedLists.length < this.total){
this.getguanzhulist()
}
}else{
console.log('附近');
if(this.feedList.length < this.total){
this.getdongtailist()
}
}
},
// 下拉刷新最新的数据
onRefresh() {
this.isRefreshing = true
setTimeout(() => {
this.pageNum = 1
this.isRefreshing = false
if(this.currentTab == 1){
this.currLat = ''
this.currLon = ''
this.getdongtailist()
}else if(this.currentTab == 0){
this.getguanzhulist()
}else{
console.log('附近');
this.getdongtailist()
}
}, 300)
},
}
}
</script>
<style lang="scss">
page {
background:#fff;
border-radius: 0rpx 0rpx 0rpx 0rpx;
}
.waterfall-container {
display: flex;
gap: 20rpx;
padding: 0 20rpx;
.waterfall-left,
.waterfall-right {
flex: 1;
}
}
.demo-warter {
border-radius: 10rpx;
margin-bottom: 20rpx;
background-color: #ffffff;
padding-bottom: 20rpx;
box-shadow: 0rpx 6rpx 16rpx 0rpx rgba(0,0,0,0.1);
border-radius: 10rpx 10rpx 10rpx 10rpx;
position: relative;
overflow: hidden;
.video-holder{
width: 100%;
border-radius: 10rpx 10rpx 0 0;
overflow: hidden;
background-color: #000;
}
.feed-video{
width: 100%;
display: block;
object-fit: cover;
}
.shuju{
display: flex;
align-items: center;
margin-top: 10rpx;
justify-content: flex-end;
view{
font-size: 14rpx;
color: #3D3D3D;
margin-left: 32rpx;
image{
width: 20rpx;
height: 20rpx;
margin-right: 4rpx;
}
display: flex;
align-items: center;
}
}
.cont{
font-size: 24rpx;
color: #3D3D3D;
padding: 0 18rpx;
margin-top: 10rpx;
display: flex;
align-items: center;
justify-content: space-between;
.lt{
display: flex;
align-items: center;
image{
width: 32rpx;
height: 32rpx;
margin-right: 8rpx;
border-radius: 50%;
}
}
.rt{
display: flex;
align-items: center;
image{
width: 28rpx;
height: 28rpx;
margin-right: 8rpx;
border-radius: 50%;
}
}
}
.dizhi{
margin-top: 16rpx;
padding-left: 18rpx;
font-weight: 600;
font-size: 28rpx;
color: #3D3D3D;
}
}
.page { display: flex; flex-direction: column; height: 100vh; }
.header {
padding: 10rpx 24rpx 0;
background: #fff;
z-index: 10;
margin-top: 84rpx;
.nav {
display: flex;
padding-left: 82rpx;
gap: 70rpx;
margin-bottom: 20rpx;
.nav-item {
font-size: 32rpx;
color: #3D3D3D;
padding: 12rpx 6rpx;
&.active {
color: #48893B !important;
position: relative;
font-weight: 600;
font-size: 36rpx;
color: #3D3D3D;
}
}
}
.search-box {
display: flex;
align-items: center;
gap: 16rpx;
padding-bottom: 16rpx;
margin-top: 36rpx;
.search-input {
flex: 1;
background: #f5f6f7;
border-radius: 999rpx;
height: 72rpx;
padding: 0 28rpx;
display: flex;
align-items: center;
.iconfont {
margin-right: 12rpx;
color: #999;
}
image{
width: 32rpx;
height: 32rpx;
margin-right: 16rpx;
}
.placeholder { color: #999; }
}
.search-btn {
width: 66rpx;
height: 66rpx;
image{
width: 66rpx;
height: 66rpx;
}
}
}
}
.feed-swiper { flex: 1; }
.feed {
width: 750rpx;
margin: auto;
height: 73vh;
overflow: scroll;
padding-bottom: 100rpx;
.feed-card {
padding: 24rpx 40rpx;
box-sizing: border-box;
.card-header {
display: flex;
.avatar {
width: 72rpx;
height: 72rpx;
border-radius: 50%;
margin-right: 16rpx;
}
.meta { flex: 1; }
.name-row { display: flex; align-items: center; justify-content: space-between; }
.name { font-weight: 600; color: #333; }
.follow-btn {
padding: 6rpx 20rpx;
border-radius: 999rpx;
background: #00c27a;
color: #fff;
&.followed { background: #f0f0f0; color: #666; }
}
.time { color: #999; font-size: 24rpx; }
}
.card-content {
margin-top: 12rpx;
padding-left: 90rpx;
.text { color: #333; }
.thumb { width: 98px; height: 98px; border-radius: 12rpx; margin-top: 12rpx; }
.video-thumb { width: 98px; height: 98px; margin-top: 12rpx; border-radius: 12rpx; overflow: hidden; }
.video-thumb video { width: 98px; height: 98px; object-fit: cover; display: block; }
// 单图等比缩放最大宽度100%
.thumb-single {
margin-top: 12rpx;
image { width: 98px; height: 98px; border-radius: 12rpx; display: block; }
video { width: 98px; height: 98px; border-radius: 12rpx; object-fit: cover; display: block; }
}
// 多图正方形九宫格自适应裁剪
.thumb-grid {
margin-top: 12rpx;
display: grid;
grid-template-columns: repeat(3, 98px);
gap: 10rpx;
.grid-item {
position: relative;
width: 98px; height: 98px;
image, video {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
width: 98px; height: 98px;
border-radius: 8rpx;
}
}
}
}
.dizhi{
font-weight: 600;
font-size: 26rpx;
color: #1EC28B;
display: flex;
align-items: center;
margin-top: 10rpx;
padding-left: 90rpx;
.qian{
width: 26rpx;
height: 26rpx;
margin-right: 8rpx;
}
.hou{
width: 32rpx;
height: 32rpx;
margin-left: 4rpx;
}
}
.card-actions {
margin-top: 16rpx;
display: flex;
justify-content: space-between;
gap: 32rpx;
color: #666;
padding-left: 90rpx;
image{
width: 32rpx;
height: 32rpx;
}
.action { display: flex; align-items: center; }
.num { margin-left: 8rpx; }
}
}
}
</style>