fjrcloud-community-app/pages/sub/community/dynamics.vue

322 lines
7.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!-- 社区动态页面 -->
<template>
<s-layout title="社区动态" navbar="inner" color="#333333">
<!-- 渐变背景 -->
<view class="gradient-bg"></view>
<view class="community-dynamics-page">
<!-- Tab 切换栏 -->
<view class="tab-bar">
<view
class="tab-item"
v-for="(tab, index) in tabList"
:key="index"
:class="{ active: currentTab === index }"
@tap="switchTab(index)"
>
<text class="tab-text">{{ tab }}</text>
<view class="tab-indicator" v-if="currentTab === index"></view>
</view>
</view>
<!-- 动态列表 - 独立滚动区域 -->
<scroll-view class="dynamics-list" scroll-y :style="{ height: scrollViewHeight + 'px' }">
<view class="list-inner">
<view
class="dynamics-item"
v-for="(item, index) in dynamicsList"
:key="index"
@tap="goDetail(item)"
>
<!-- 封面图 -->
<image class="item-cover" :src="item.cover" mode="aspectFill" />
<!-- 内容区 -->
<view class="item-content">
<text class="item-title">{{ item.title }}</text>
<view class="item-footer">
<text class="item-views">{{ item.views||0 }}人浏览</text>
<text class="item-date">{{ item.date }}</text>
</view>
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" v-if="dynamicsList.length === 0">
<text class="empty-text"></text>
</view>
</view>
</scroll-view>
</view>
</s-layout>
</template>
<script setup>
import { ref, onMounted, nextTick, getCurrentInstance, computed } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import DynamicsApi from '@/sheep/api/community/dynamics';
import sheep from '@/sheep';
// 列表滚动区域高度单位px通过JS计算后绑定到scroll-view
const scrollViewHeight = ref(0);
// Tab 列表
const tabList = ref(['全部', '物业', '业委会', '社区']);
const currentTab = ref(0);
// 动态列表
const dynamicsList = ref([]);
// 分页参数
const pageNo = ref(1);
const pageSize = ref(10);
const total = ref(0);
const loading = ref(false);
const noMore = ref(false);
// 当前小区ID
const communityId = computed(() => {
return sheep.$store('user').userInfo?.currentCommunityId || null;
});
// Tab 类型映射
const tabTypeMap = {
0: null, // 全部
1: 1, // 物业
2: 2, // 业委会
3: 3, // 社区
};
// 格式化浏览量
function formatViewCount(count) {
if (!count && count !== 0) return '0';
if (count >= 10000) {
return (count / 10000).toFixed(1) + '万';
}
return String(count);
}
// 页面加载
onLoad((options) => {
if (options.tab) {
currentTab.value = parseInt(options.tab);
}
loadDynamicsList();
});
// 页面渲染完成后计算scroll-view的精确高度
onMounted(() => {
const instance = getCurrentInstance();
nextTick(() => {
const sysInfo = uni.getSystemInfoSync();
// 获取tab栏的实际渲染高度
uni.createSelectorQuery()
.in(instance)
.select('.tab-bar')
.boundingClientRect((rect) => {
if (rect) {
// scroll-view高度 = 屏幕可用高度 - tab栏高度 - tab栏距离顶部的高度
scrollViewHeight.value = sysInfo.windowHeight - rect.height - rect.top;
}
})
.exec();
});
});
// 切换 Tab
function switchTab(index) {
currentTab.value = index;
pageNo.value = 1;
noMore.value = false;
loadDynamicsList();
}
// 加载动态列表
async function loadDynamicsList() {
if (loading.value) return;
loading.value = true;
const params = {
pageNo: pageNo.value,
pageSize: pageSize.value,
};
const postType = tabTypeMap[currentTab.value];
if (postType) {
params.postType = postType;
}
if (communityId.value) {
params.communityId = communityId.value;
}
const { code, data } = await DynamicsApi.getPage(params);
loading.value = false;
if (code === 0 && data) {
const list = (data.list || []).map((item) => ({
id: item.id,
title: item.title,
cover: item.coverImage || '/static/img/guest.png',
views: formatViewCount(item.viewCount),
date: item.publishTime ? sheep.$helper.timeFormat(item.publishTime, 'yyyy/mm/dd') : '',
}));
if (pageNo.value === 1) {
dynamicsList.value = list;
} else {
dynamicsList.value = dynamicsList.value.concat(list);
}
total.value = data.total || 0;
noMore.value = dynamicsList.value.length >= total.value;
}
}
// 加载更多
function loadMore() {
if (noMore.value || loading.value) return;
pageNo.value += 1;
loadDynamicsList();
}
// 跳转详情
function goDetail(item) {
uni.navigateTo({
url: `/pages/sub/community/dynamics-detail?id=${item.id}`
});
}
</script>
<style lang="scss" scoped>
/* 渐变背景 */
.gradient-bg {
position: fixed;
top: 0;
left: 0;
width: 750rpx;
height: 660rpx;
background: linear-gradient(180deg, #F8EDE8 0%, #F5F5F5 50%);
z-index: 0;
pointer-events: none;
}
/* 页面容器 */
.community-dynamics-page {
position: relative;
z-index: 1;
}
/* Tab 切换栏 */
.tab-bar {
display: flex;
align-items: center;
justify-content: space-around;
padding: 36rpx 50rpx;
// background-color: #FFFFFF;
.tab-item {
position: relative;
padding: 8rpx 16rpx;
.tab-text {
font-size: 30rpx;
color: #999999;
transition: all 0.3s;
}
&.active .tab-text {
font-size: 32rpx;
font-weight: 600;
color: #333333;
}
.tab-indicator {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 48rpx;
height: 6rpx;
background: linear-gradient(90deg, #FF7F69 0%, #FC5A5D 100%);
border-radius: 3rpx;
}
}
}
/* 动态列表 - scroll-view高度由JS动态绑定 */
.dynamics-list {
/* 高度由 :style="{ height: scrollViewHeight + 'px' }" 控制 */
}
/* 列表内容包裹层 - 负责padding间距 */
.list-inner {
padding: 24rpx 32rpx;
}
/* 动态项 */
.dynamics-item {
display: flex;
background-color: #FFFFFF;
border-radius: 31rpx;
padding: 24rpx;
margin-bottom: 19rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
.item-cover {
width: 305rpx;
height: 168rpx;
border-radius: 19rpx;
flex-shrink: 0;
}
.item-content {
flex: 1;
margin-left: 24rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
.item-title {
font-size: 30rpx;
font-weight: 500;
color: #333333;
line-height: 1.5;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
}
.item-footer {
display: flex;
align-items: center;
justify-content: space-between;
.item-views {
font-size: 24rpx;
color: #999999;
}
.item-date {
font-size: 24rpx;
color: #999999;
}
}
}
}
/* 空状态 */
.empty-state {
display: flex;
align-items: center;
justify-content: center;
padding: 200rpx 0;
.empty-text {
font-size: 28rpx;
color: #999999;
}
}
</style>