Files
product-uniapp/pages/square/index.vue
T
2025-12-13 17:30:18 +08:00

300 lines
6.6 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">
<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>