fjrcloud-community-app/pages/sub/knowledge/classroom.vue

393 lines
8.8 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="knowledge-classroom-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="classroom-list" scroll-y :style="{ height: scrollViewHeight + 'px' }" v-if="classroomList.length > 0">
<view class="list-inner" :class="{ 'grid-layout': currentTab === 1 }">
<view
class="classroom-item"
v-for="(item, index) in classroomList"
:key="index"
@tap="goDetail(item)"
>
<!-- 封面图 -->
<view class="item-cover-wrap">
<image class="item-cover" :src="item.cover" mode="aspectFill" />
</view>
<!-- 内容区 -->
<view class="item-content">
<text class="item-title">{{ item.title }}</text>
<view class="item-footer" v-if="currentTab === 0">
<text class="item-date">{{ item.date }}</text>
</view>
<view class="item-footer" v-else>
<view class="item-stat">
<text class="stat-icon">👁</text>
<text class="stat-text">{{ item.views }}</text>
</view>
<view class="item-stat">
<text class="stat-icon">♡</text>
<text class="stat-text">{{ item.likes }}</text>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
<!-- 空状态 -->
<view class="empty-state" v-else>
<text class="empty-text"></text>
</view>
</view>
</s-layout>
</template>
<script setup>
import { ref, onMounted, nextTick, getCurrentInstance, computed } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import KnowledgeApi from '@/sheep/api/community/knowledge';
import sheep from '@/sheep';
// 列表滚动区域高度单位px通过JS计算后绑定到scroll-view
const scrollViewHeight = ref(0);
// Tab 列表
const tabList = ref(['法律小课堂', '小区治理']);
const currentTab = ref(0);
// 知识课堂列表
const classroomList = 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: 1, // 法律小课堂
1: 2, // 小区治理
};
// 格式化数量
function formatCount(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);
}
loadClassroomList();
});
// 页面渲染完成后计算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;
loadClassroomList();
}
// 加载知识课堂列表
async function loadClassroomList() {
if (loading.value) return;
loading.value = true;
const params = {
pageNo: pageNo.value,
pageSize: pageSize.value,
};
const classType = tabTypeMap[currentTab.value];
if (classType) {
params.classType = classType;
}
if (communityId.value) {
params.communityId = communityId.value;
}
const { code, data } = await KnowledgeApi.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: formatCount(item.viewCount),
likes: formatCount(item.likeCount),
date: item.createTime ? sheep.$helper.timeFormat(item.createTime, 'yyyy/mm/dd hh:MM') : '',
}));
if (pageNo.value === 1) {
classroomList.value = list;
} else {
classroomList.value = classroomList.value.concat(list);
}
total.value = data.total || 0;
noMore.value = classroomList.value.length >= total.value;
}
}
// 加载更多
function loadMore() {
if (noMore.value || loading.value) return;
pageNo.value += 1;
loadClassroomList();
}
// 跳转详情
function goDetail(item) {
uni.navigateTo({
url: `/pages/sub/knowledge/detail?id=${item.id}&tab=${currentTab.value}`
});
}
</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;
}
/* 页面容器 */
.knowledge-classroom-page {
position: relative;
z-index: 1;
}
/* Tab 切换栏 */
.tab-bar {
display: flex;
align-items: center;
justify-content: space-around;
padding: 36rpx 50rpx;
.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动态绑定 */
.classroom-list {
/* 高度由 :style="{ height: scrollViewHeight + 'px' }" 控制 */
}
/* 列表内容包裹层 - 负责padding间距 */
.list-inner {
padding: 24rpx 32rpx;
&.grid-layout {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
}
/* 知识课堂项 */
.classroom-item {
display: flex;
background-color: #FFFFFF;
border-radius: 16rpx;
padding: 24rpx;
margin-bottom: 19rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
.grid-layout & {
width: 335rpx;
flex-direction: column;
padding: 0;
overflow: hidden;
}
.item-cover-wrap {
position: relative;
flex-shrink: 0;
.grid-layout & {
width: 100%;
}
.item-cover {
width: 305rpx;
height: 168rpx;
border-radius: 12rpx;
.grid-layout & {
width: 100%;
height: 200rpx;
border-radius: 0;
}
}
.play-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 80rpx;
height: 80rpx;
background: rgba(255, 255, 255, 0.9);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
.play-img {
width: 40rpx;
height: 40rpx;
}
}
}
.item-content {
flex: 1;
margin-left: 24rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
.grid-layout & {
margin-left: 0;
padding: 16rpx;
}
.item-title {
font-size: 28rpx;
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;
margin-top: 12rpx;
.item-date {
font-size: 24rpx;
color: #999999;
}
.item-stat {
display: flex;
align-items: center;
.stat-icon {
font-size: 24rpx;
margin-right: 6rpx;
}
.stat-text {
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>