mcwl-pc/app/pages/planet/index.vue

212 lines
6.8 KiB
Vue

<script setup lang="ts">
import { commonApi } from '@/api/common'
import { useRouter } from 'vue-router'
const router = useRouter()
definePageMeta({
layout: 'planet',
})
const listParams = ref({
communityTag: null as string | null,
pageNum: 1,
pageSize: 12,
})
const containerRef = ref<HTMLElement | undefined>(undefined)
// 标签
interface CommunityTag {
dictLabel: string
dictValue: string | null
}
const communityTagList = ref<CommunityTag[]>([])
async function getDictType() {
try {
const res = await commonApi.dictType({ type: 'community_tag' })
if (res.code === 200) {
communityTagList.value = [{
dictLabel: '全部',
dictValue: null,
}, ...res.data] as CommunityTag[]
}
}
catch (error) {
console.error(error)
}
}
function changeTag(type: string | null) {
listParams.value.communityTag = type
initGetList()
}
getDictType()
interface ApiResponse<T> {
code: number
rows: T[]
total: number
}
interface CommunityItem {
imageUrl: string
publishNum: number
communityName: string
avatar: string
createBy: string
createDay: number
description: string
price: number | null
}
// 获取列表
const listFinish = ref(false)
const loading = ref(false)
const dataList = ref<CommunityItem[]>([])
function initGetList() {
listFinish.value = false
listParams.value.pageNum = 1
getList()
}
async function getList() {
try {
if (listFinish.value || loading.value) // 添加loading检查,避免重复请求
return
loading.value = listParams.value.pageNum === 1 // 只在第一页显示loading
const res = await request.post<ApiResponse<CommunityItem>>('/community/list', listParams.value)
if (res.code === 200) {
if (listParams.value.pageNum === 1) {
dataList.value = res.rows
}
else {
dataList.value = [...dataList.value, ...res.rows]
}
if (dataList.value.length >= res.total) {
listFinish.value = true
}
listParams.value.pageNum++
}
}
catch (error) {
console.error(error)
}
finally {
loading.value = false
}
}
getList()
function goDetail(id: string) {
router.push(`/planet-detail/${id}`)
}
</script>
<template>
<div class="min-h-screen bg-[#f7f8fa] relative">
<n-affix
:trigger-top="0"
position="absolute"
:listen-to="() => containerRef"
>
<div class="px-10 bg-[#fff] sticky top-0 left-0 right-0 z-10">
<div class="flex flex-wrap gap-2 py-4">
<div
v-for="(item, index) in communityTagList"
:key="index"
class="px-[12px] py-[9px] text-sm rounded-lg cursor-pointer"
:class="{ 'bg-black text-white': listParams.communityTag === item.dictValue, 'bg-white text-[#878d95] hover:bg-gray-100': listParams.communityTag !== item.dictValue }"
@click="changeTag(item.dictValue)"
>
{{ item.dictLabel }}
</div>
</div>
</div>
</n-affix>
<article class="px-10 py-6">
<n-infinite-scroll :distance="10" trigger="once" @load="getList">
<!-- 添加trigger="once"属性 -->
<div v-if="loading" class="grid grid-cols-3 gap-2">
<div v-for="i in 9" :key="i" class="bg-white rounded-lg overflow-hidden shadow-sm flex p-4">
<n-skeleton class="w-[161px] h-[161px] rounded-lg flex-shrink-0" />
<div class="flex flex-col gap-2 px-4 flex-1">
<div class="flex flex-col gap-2">
<n-skeleton text :width="140" />
<div class="flex items-center gap-2">
<n-skeleton circle width="20px" height="20px" />
<n-skeleton text :width="60" />
<n-skeleton text :width="80" />
</div>
<n-skeleton text :repeat="2" />
</div>
<n-skeleton text :width="60" />
</div>
</div>
</div>
<div v-else-if="dataList.length > 0" class="grid grid-cols-3 gap-2">
<PlanetItem v-for="(item, index) in dataList" :key="index" :item="item" type="all" />
<!--
<div v-for="(item, index) in dataList" :key="index" class="bg-white rounded-lg overflow-hidden shadow-sm flex p-4 cursor-pointer hover:shadow-[0_4px_14px_0_rgba(0,0,0,0.1)] hover:-translate-y-1 transition-all duration-300" @click="goDetail(item.id)">
<div class="w-[161px] h-[161px] relative rounded-lg">
<img class="w-full h-full object-cover rounded-lg" :src="item.imageUrl" alt="">
<span class="absolute bottom-2 left-2 text-white text-xs">{{ item.publishNum || 0 }}人已经加入</span>
</div>
<div class="flex flex-col gap-2 px-4 flex-1 justify-between">
<div class="flex flex-col gap-2">
<div class="text-base font-bold">
{{ item.communityName }}
</div>
<div class="flex items-center gap-2 text-xs text-[#878d95]">
<img class="w-[20px] h-[20px] rounded-full" :src="item.avatar" alt="">
<div>
{{ item.nickName }}
</div>
<div>创建{{ item.createDay || 0 }}天</div>
</div>
<div class="text-sm text-[#4a5563] line-clamp-3">
{{ item.description }}
</div>
</div>
<div class="text-[#fc4141]">
<div v-if="item.price">
<span class="text-base font-bold mr-1">
{{ item.price }}
</span>
<span class="text-xs">
金币
</span>
</div>
<div v-else>
免费
</div>
</div>
</div>
</div> -->
</div>
<div v-if="dataList.length === 0 && listFinish" class="flex flex-col items-center justify-center py-12">
<div class="w-48 h-48 mb-4 flex items-center justify-center">
<div class="relative">
<div class="w-32 h-32 rounded-full border-4 border-gray-200" />
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-24 h-24 rounded-full border-4 border-gray-100" />
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-16 h-16 rounded-full bg-gray-50" />
</div>
</div>
<p class="text-gray-500 mb-4">
这里空空如也,什么都没有找到~
</p>
<!-- <n-button type="primary" size="small" class="px-6">
去发现更多
</n-button> -->
</div>
</n-infinite-scroll>
</article>
</div>
</template>
<style lang="scss" scoped>
.line-clamp-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
</style>