300 lines
6.6 KiB
Vue
300 lines
6.6 KiB
Vue
<template>
|
||
<view class="page">
|
||
<uni-nav-bar :fixed="true" :border="false" color="#000" backgroundColor="#fff" :statusBar="true" title="广场" />
|
||
<!-- Tabs -->
|
||
<view class="tabs">
|
||
<view :class="['tab', currentTab==='latest'?'on':'']" @click="changeTab('latest')">最新发布</view>
|
||
<view class="divider"></view>
|
||
<view :class="['tab', currentTab==='near'?'on':'']" @click="changeTab('near')">距离最近</view>
|
||
</view>
|
||
|
||
<!-- Feed list -->
|
||
<scroll-view
|
||
scroll-y
|
||
class="list-scroll"
|
||
refresher-enabled
|
||
:refresher-triggered="refreshing"
|
||
@refresherrefresh="onRefresh"
|
||
:lower-threshold="100"
|
||
@scrolltolower="onLoadMore"
|
||
>
|
||
<view class="feed-list">
|
||
<post-card
|
||
v-for="sitem in slist"
|
||
:key="sitem.id || sitem.username"
|
||
:item="sitem"
|
||
@userClick="goto"
|
||
@view="goto"
|
||
@contact="handleContact"
|
||
@comment="handleComment">
|
||
</post-card>
|
||
|
||
<!-- 状态提示 -->
|
||
<view v-if="hasMore" class="load-more">
|
||
<text v-if="loadingMore">加载中...</text>
|
||
<text v-else>上拉加载更多</text>
|
||
</view>
|
||
<view v-else-if="slist.length > 0" class="load-more">
|
||
<text>没有更多了</text>
|
||
</view>
|
||
<view class="empty" v-if="slist.length === 0 && !loading">
|
||
<image src="/static/image/empty.png" mode="aspectFit"></image>
|
||
<view>暂无数据!</view>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
|
||
<!-- 加载提示 -->
|
||
<view v-if="loading" class="loading-mask">
|
||
<view class="loading-text">加载中...</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
<script>
|
||
import { request } from '@/api/apiT.js'
|
||
import PostCard from '@/components/PostCard.vue'
|
||
export default {
|
||
components: { PostCard },
|
||
data() {
|
||
return {
|
||
tabs: [
|
||
{ key: 'latest', label: '最新发布' },
|
||
{ key: 'near', label: '距离最近' }
|
||
],
|
||
currentTab: 'latest',
|
||
slist:[],
|
||
loading: false,
|
||
refreshing: false,
|
||
loadingMore: false,
|
||
page: 1,
|
||
pageSize: 10,
|
||
hasMore: true,
|
||
latitude:'',
|
||
longitude:''
|
||
}
|
||
},
|
||
onShow() {
|
||
this.loadList()
|
||
this.getFuzzy().then(res => {
|
||
this.latitude = res.latitude
|
||
this.longitude = res.longitude
|
||
console.log(res);
|
||
}).catch(err => console.error(err));
|
||
// this.syncTabbar()
|
||
},
|
||
methods: {
|
||
getFuzzy() {
|
||
return new Promise((resolve, reject) => {
|
||
wx.getSetting({
|
||
success: (st) => {
|
||
const ok = st.authSetting['scope.userFuzzyLocation'];
|
||
const run = () => wx.getFuzzyLocation({
|
||
type: 'wgs84',
|
||
success: resolve,
|
||
fail: reject
|
||
});
|
||
|
||
if (ok) return run();
|
||
|
||
wx.authorize({
|
||
scope: 'scope.userFuzzyLocation',
|
||
success: run,
|
||
fail: () => wx.openSetting({ success: () => reject(new Error('未授权')) })
|
||
});
|
||
},
|
||
fail: reject
|
||
});
|
||
});
|
||
},
|
||
handleContact(item) {
|
||
const phone = item.user.mobile
|
||
if (!phone) return uni.showToast({ title: '号码为空', icon: 'none' });
|
||
// 简单清洗:去空格/横杠
|
||
const num = String(phone).replace(/[^\d+]/g, '');
|
||
uni.makePhoneCall({ phoneNumber: num });
|
||
},
|
||
changeTab(key) {
|
||
if (this.currentTab === key) return
|
||
this.currentTab = key
|
||
this.page = 1
|
||
this.hasMore = true
|
||
this.slist = []
|
||
this.loadList()
|
||
},
|
||
loadList(isLoadMore = false) {
|
||
if (isLoadMore) {
|
||
if (this.loadingMore || this.loading || this.refreshing || !this.hasMore) return
|
||
this.loadingMore = true
|
||
this.page += 1
|
||
} else {
|
||
if (this.loading || this.loadingMore) return
|
||
this.loading = true
|
||
this.page = 1
|
||
this.hasMore = true
|
||
this.slist = []
|
||
}
|
||
const collectUrl = this.currentTab=='latest' ? 'common/post/list' : 'common/post/nearby'
|
||
var that = this;
|
||
const params = {
|
||
current:this.page,
|
||
status:1,
|
||
size:10
|
||
};
|
||
// 添加排序参数(如果后端支持)
|
||
if(this.currentTab=='near'){
|
||
params.lng = this.longitude;
|
||
params.lat = this.latitude;
|
||
} else {
|
||
}
|
||
request({
|
||
url: collectUrl,
|
||
method: 'GET',
|
||
data: params
|
||
}).then(res => {
|
||
this.loading = false
|
||
this.loadingMore = false
|
||
this.refreshing = false
|
||
if (res.data.code === 200) {
|
||
const records = res.data.data.records || []
|
||
const total = res.data.data.total || 0
|
||
if (isLoadMore) {
|
||
this.slist = [...this.slist, ...records]
|
||
} else {
|
||
this.slist = records
|
||
}
|
||
this.hasMore = this.slist.length < total
|
||
}
|
||
}).catch(() => {
|
||
this.loading = false
|
||
this.loadingMore = false
|
||
this.refreshing = false
|
||
if (isLoadMore) {
|
||
this.page -= 1
|
||
}
|
||
})
|
||
},
|
||
onRefresh() {
|
||
if (this.loading || this.loadingMore) {
|
||
this.refreshing = false
|
||
return
|
||
}
|
||
this.refreshing = true
|
||
this.loadList(false)
|
||
},
|
||
onLoadMore() {
|
||
this.loadList(true)
|
||
},
|
||
navToList(item) {
|
||
uni.navigateTo({
|
||
url: '/pages/square/detiles?id=' + item.id
|
||
})
|
||
},
|
||
leftClick() {
|
||
uni.navigateBack()
|
||
}
|
||
},
|
||
computed: {
|
||
underlineTransform() {
|
||
const index = this.tabs.findIndex(t => t.key === this.currentTab)
|
||
return `translateX(${index * 50}%)`
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
page,
|
||
.page {
|
||
height: 100%;
|
||
background: #f8f8f8;
|
||
}
|
||
|
||
.tabs {
|
||
height: 80rpx;
|
||
background: #fff;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-around;
|
||
gap: 24rpx;
|
||
position: relative;
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
}
|
||
.tab {
|
||
position: relative;
|
||
padding: 12rpx 20rpx 18rpx;
|
||
color: #333;
|
||
}
|
||
.tab::after {
|
||
content: '';
|
||
position: absolute;
|
||
left: 50%;
|
||
bottom: 4rpx;
|
||
width: 50rpx;
|
||
height: 4rpx;
|
||
background: #05b3a8;
|
||
border-radius: 4rpx;
|
||
transform: translateX(-50%) scaleX(0);
|
||
transition: transform 0.2s;
|
||
}
|
||
.tab.on {
|
||
color: #05b3a8;
|
||
font-weight: 600;
|
||
}
|
||
.tab.on::after {
|
||
transform: translateX(-50%) scaleX(1);
|
||
}
|
||
.divider {
|
||
width: 1px;
|
||
height: 26rpx;
|
||
background: #dcdcdc;
|
||
}
|
||
|
||
.list-scroll {
|
||
height: calc(100vh - 120rpx);
|
||
}
|
||
|
||
.feed-list {
|
||
// padding: 20rpx;
|
||
margin: 20rpx 30rpx;
|
||
// background: #fff;
|
||
}
|
||
.load-more {
|
||
width: 100%;
|
||
text-align: center;
|
||
padding: 30rpx 0;
|
||
font-size: 26rpx;
|
||
color: #999;
|
||
}
|
||
.empty {
|
||
width: 100%;
|
||
text-align: center;
|
||
padding: 100rpx 0;
|
||
}
|
||
.empty image {
|
||
width: 252rpx;
|
||
height: 164rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.loading-mask {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.3);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 999;
|
||
|
||
.loading-text {
|
||
color: #fff;
|
||
font-size: 28upx;
|
||
background-color: rgba(0, 0, 0, 0.7);
|
||
padding: 20upx 40upx;
|
||
border-radius: 8upx;
|
||
}
|
||
}
|
||
</style> |