Files
panel-uniapp/pages/square/index.vue
T
2025-12-03 14:07:17 +08:00

449 lines
10 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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="content">
<uni-nav-bar leftText=" " :fixed="true" :border="false" @clickLeft="leftClick" color="#000000" backgroundColor="#fff" :statusBar="true" title="广场"></uni-nav-bar>
<view class="content-con">
<scroll-view scroll-y class="left-aside">
<view v-for="item in flist" :key="item.id" class="f-item b-b" :class="{active: item.id === currentCategoryId}"
@click="onCategoryChange(item.id)">
<view class="category-icon" v-if="item.icon_active_pull">
<image :src="item.id === currentCategoryId?item.icon_active_pull:item.icon_inactive_pull" mode=""></image>
️</view>
{{item.name}}
</view>
</scroll-view>
<scroll-view scroll-y class="right-aside"
refresher-enabled
:refresher-triggered="refreshing"
@refresherrefresh="onRefresh"
:lower-threshold="100"
@scrolltolower="onLoadMore">
<view class="t-lists">
<square-post-card
class="t-item"
v-for="sitem in slist"
:key="sitem.id"
:item="sitem"
:isshow="true"
@view="navToList"
@comment="navTomsg"
@like="navTozan" />
<!-- 加载更多提示 -->
<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">
<image src="/static/image/empty.png" mode=""></image>
<view class="">
暂无数据!
</view>
</view>
</view>
</scroll-view>
</view>
<!-- 加载提示 -->
<view v-if="loading" class="loading-mask">
<view class="loading-text">加载中...</view>
</view>
</view>
</template>
<script>
import { request,showToast } from '@/api/apiT.js'
import SquarePostCard from '@/components/SquarePostCard.vue'
export default {
components: {
SquarePostCard
},
data() {
return {
flist: [],
slist: [],
currentCategoryId: '', // 当前选中的分类id
loading: false, // 加载状态
refreshing: false, // 下拉刷新状态
loadingMore: false, // 上拉加载状态
page: 1, // 当前页码
pageSize: 10, // 每页数量
hasMore: true, // 是否还有更多数据
categoriesLoaded: false // 分类是否已加载完成
}
},
onLoad() {
// 加载第一级分类列表
},
onShow() {
this.loadCategoryList();
this.syncTabbar()
// // 从详情页返回后,重新拉取当前分类数据
// if (this.categoriesLoaded) {
// this.refreshCurrentCategory()
// }
},
methods: {
// 加载第一级分类列表
loadCategoryList() {
// TODO: 替换为实际的后端接口
let that = this;
request({
url:'common/post/category/list',
method:'GET'
}).then(res => {
if (res.data.code == 200) {
const records = res.data.data.records || [];
this.flist = [{
id: '',
name: '全部分类'
}, ...records];
this.categoriesLoaded = true;
// 默认加载第一个分类的数据
if (this.flist.length > 0) {
this.onCategoryChange(this.flist[0].id);
}
}
})
},
// 重新加载当前分类数据
refreshCurrentCategory() {
const targetCategory = this.currentCategoryId !== undefined ? this.currentCategoryId : (this.flist[0] && this.flist[0].id) || '';
this.loadCategoryData(targetCategory, false);
},
// 分类切换事件
onCategoryChange(categoryId) {
// 如果点击的是当前分类且已有数据,不重复加载
if (this.currentCategoryId === categoryId && this.slist.length > 0) {
return;
}
// 切换分类时,重置所有状态
this.currentCategoryId = categoryId;
this.page = 1;
this.hasMore = true;
this.loading = false;
this.loadingMore = false;
this.refreshing = false;
this.slist = []; // 先清空数据
this.loadCategoryData(categoryId, false);
},
// 根据分类id加载分类下的内容
loadCategoryData(categoryId, isLoadMore = false) {
// 防止重复请求:如果是加载更多,需要检查所有加载状态
if (isLoadMore) {
if (this.loadingMore || this.loading || this.refreshing) {
return;
}
} else {
// 下拉刷新或初次加载,检查加载状态
if (this.loading || this.loadingMore) {
return;
}
}
if (isLoadMore) {
this.loadingMore = true;
this.page += 1;
} else {
this.loading = true;
this.page = 1;
this.hasMore = true;
this.slist = []; // 清空之前的数据
}
request({
url:'common/post/list',
method:'GET',
data:{
category_id:categoryId,
current: this.page,
size: this.pageSize
}
}).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) {
// 上拉加载更多,追加数据并去重
const existingIds = new Set(this.slist.map(item => item.id));
const newRecords = records.filter(item => !existingIds.has(item.id));
this.slist = [...this.slist, ...newRecords];
} 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.loadCategoryData(this.currentCategoryId, false);
},
// 上拉加载更多
onLoadMore() {
if (!this.hasMore || this.loadingMore || this.loading || this.refreshing) {
return;
}
this.loadCategoryData(this.currentCategoryId, true);
},
// 点击商品项
navToList(item) {
uni.navigateTo({
url: '/pages/square/detiles?id='+item.id
});
},
//点赞
navTozan(item){
const targetIndex = this.slist.findIndex(post => post.id === item.id)
if(targetIndex === -1){
return
}
const target = this.slist[targetIndex]
const isLiked = Number(target.is_like) === 1
const likeUrl = isLiked ? 'common/post/like/destroy' : 'common/post/like/store'
const method = isLiked ? 'GET' : 'POST'
const data = {
post_id: target.id
}
if (isLiked) {
data.user_id = target.user_id
}
request({
url: likeUrl,
method,
data
}).then(res => {
if(res.data.code === 200){
const newTarget = { ...target }
if(isLiked){
newTarget.is_like = 0
newTarget.like = Math.max(0, (Number(newTarget.like) || 0) - 1)
uni.showToast({
title: '取消成功',
icon: 'none'
});
}else{
newTarget.is_like = 1
newTarget.like = (Number(newTarget.like) || 0) + 1
uni.showToast({
title: '点赞成功',
icon: 'none'
});
}
this.$set(this.slist, targetIndex, newTarget)
}else{
uni.showToast({
title:res.data.message,
icon: 'none'
});
}
})
},
//消息
navTomsg(item){
request({
url:'common/like/store',
method:'GET',
data:{
post_id:item.id
}
}).then(res => {
})
},
leftClick(){
uni.navigateBack()
},
syncTabbar(){
uni.setTabBarItem({ index:0, text:this.$t('tabbar.home') })
uni.setTabBarItem({ index:1, text:this.$t('tabbar.square') })
uni.setTabBarItem({ index:2, text:this.$t('tabbar.publish') })
uni.setTabBarItem({ index:3, text:this.$t('tabbar.mine') })
}
}
}
</script>
<style lang='scss'>
.empty{
text-align: center;
margin-top: 30%;
width: 100%;
}
.empty image{
width: 252px;
height: 164px;
}
page,
.content {
height: 100%;
background-color: #f8f8f8;
position: relative;
}
.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;
}
}
.content-con {
height: calc(100% - 128rpx);
background-color: #f8f8f8;
display: flex;
}
.left-aside {
flex-shrink: 0;
width: 200upx;
height: 100%;
background-color: #F7F7F7;
}
.f-item {
display: flex;
align-items: center;
justify-content: flex-start;
width: 100%;
height: 90rpx;
font-size: 26rpx;
color: #666;
position: relative;
padding-left: 24rpx;
&.active {
color: #0071FC;
background: #fff;
&:before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
height: 36upx;
width: 8upx;
background-color: #0071FC;
border-radius: 0 4px 4px 0;
opacity: .8;
}
}
}
.iconview{
margin-right: 10px;
display: inline-block;
font-size: 22rpx;
}
.icons {
width: 16px;
height: 16px;
margin-right: 5px;
}
.right-aside {
flex: 1;
overflow: hidden;
/* padding-left: 20upx; */
/* padding-top: 20upx; */
background: #fff;
}
.t-lists {
display: flex;
flex-wrap: wrap;
padding: 20rpx;
justify-content: space-between;
}
.t-item{
width: 48%;
/* background: #fff; */
/* border-radius: 24rpx; */
overflow: hidden;
margin-bottom: 20rpx;
/* box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.06); */
}
.grid-image{
width: 100%;
height: 320rpx;
background: #E5E5E5;
border-radius: 10rpx;
}
.grid-footer{
padding: 20rpx;
display: flex;
align-items: center;
}
.grid-avatar{
width: 48rpx;
height: 48rpx;
border-radius: 50%;
margin-right: 12rpx;
}
.grid-info{
flex: 1;
display: flex;
flex-direction: column;
width: 70%;
}
.grid-tag{
font-size: 24rpx;
color: #3F435B;
margin-bottom: 4rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 87%;
}
.category-icon image{
height: 16px;
width: 16px;
margin-right: 10rpx;
}
.load-more{
width: 100%;
text-align: center;
padding: 30rpx 0;
font-size: 26rpx;
color: #999;
}
</style>