273 lines
5.3 KiB
Plaintext
273 lines
5.3 KiB
Plaintext
<template>
|
|
<view class="page">
|
|
<!-- 分类筛选 -->
|
|
<view class="category-bar">
|
|
<scroll-view class="category-scroll" scroll-x>
|
|
<view class="category-list">
|
|
<view
|
|
class="category-item"
|
|
:class="{ 'category-active': currentCategory == item.id }"
|
|
v-for="item in categories"
|
|
:key="item.id"
|
|
@click="selectCategory(item.id)"
|
|
>
|
|
<text
|
|
class="category-text"
|
|
:class="{ 'category-text-active': currentCategory == item.id }"
|
|
>{{ item.name }}</text>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
|
|
<!-- 案例列表 -->
|
|
<scroll-view
|
|
class="case-scroll"
|
|
scroll-y
|
|
@scrolltolower="loadMore"
|
|
>
|
|
<view class="case-list">
|
|
<case-card
|
|
v-for="item in caseList"
|
|
:key="item.id"
|
|
:caseData="item"
|
|
@click="goToDetail"
|
|
></case-card>
|
|
</view>
|
|
|
|
<!-- 加载状态 -->
|
|
<view class="load-status">
|
|
<text class="load-text" v-if="loading">加载中...</text>
|
|
<text class="load-text" v-else-if="noMore">没有更多了</text>
|
|
</view>
|
|
|
|
<!-- 空状态 -->
|
|
<view class="empty-state" v-if="!loading && caseList.length == 0">
|
|
<text class="empty-icon">📭</text>
|
|
<text class="empty-text">暂无相关案例</text>
|
|
</view>
|
|
|
|
<!-- 底部间距 -->
|
|
<view class="bottom-space"></view>
|
|
</scroll-view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="uts">
|
|
import { getCaseList } from '@/api/index.uts'
|
|
import { SOFA_CATEGORIES, PAGE_SIZE } from '@/utils/config.uts'
|
|
|
|
// 分类类型
|
|
type CategoryItem = {
|
|
id : string
|
|
name : string
|
|
}
|
|
|
|
// 案例类型
|
|
type CaseItem = {
|
|
id : string
|
|
title : string
|
|
category : string
|
|
categoryName : string
|
|
coverImage : string
|
|
material : string
|
|
duration : string
|
|
price : string
|
|
views : number
|
|
likes : number
|
|
}
|
|
|
|
// 分类列表
|
|
const categories = ref<CategoryItem[]>([])
|
|
|
|
// 当前分类
|
|
const currentCategory = ref('all')
|
|
|
|
// 案例列表
|
|
const caseList = ref<CaseItem[]>([])
|
|
|
|
// 分页
|
|
const page = ref(1)
|
|
const total = ref(0)
|
|
|
|
// 加载状态
|
|
const loading = ref(false)
|
|
const noMore = ref(false)
|
|
|
|
// 初始化分类
|
|
const initCategories = () => {
|
|
categories.value = SOFA_CATEGORIES.map((item) : CategoryItem => {
|
|
return {
|
|
id: item.id,
|
|
name: item.name
|
|
} as CategoryItem
|
|
})
|
|
}
|
|
|
|
// 选择分类
|
|
const selectCategory = (id : string) => {
|
|
if (currentCategory.value == id) return
|
|
currentCategory.value = id
|
|
page.value = 1
|
|
caseList.value = []
|
|
noMore.value = false
|
|
fetchCaseList()
|
|
}
|
|
|
|
// 获取案例列表
|
|
const fetchCaseList = async () => {
|
|
if (loading.value || noMore.value) return
|
|
|
|
loading.value = true
|
|
try {
|
|
const params = {
|
|
category: currentCategory.value,
|
|
page: page.value,
|
|
pageSize: PAGE_SIZE
|
|
} as UTSJSONObject
|
|
|
|
const res = await getCaseList(params)
|
|
const data = res.data as UTSJSONObject
|
|
// 适应后端返回格式:{ items: [], total: 0, page: 1, limit: 10 }
|
|
const list = data['items'] as UTSJSONObject[] || []
|
|
total.value = data['total'] as number || 0
|
|
|
|
const newList = list.map((item) : CaseItem => {
|
|
return {
|
|
id: item['id'] as string,
|
|
title: item['title'] as string,
|
|
category: item['category'] as string,
|
|
categoryName: item['categoryName'] as string,
|
|
coverImage: item['coverImage'] as string,
|
|
material: item['material'] as string,
|
|
duration: item['duration'] as string,
|
|
price: item['price'] as string,
|
|
views: item['views'] as number,
|
|
likes: item['likes'] as number
|
|
} as CaseItem
|
|
})
|
|
|
|
if (page.value == 1) {
|
|
caseList.value = newList
|
|
} else {
|
|
caseList.value = [...caseList.value, ...newList]
|
|
}
|
|
|
|
if (caseList.value.length >= total.value) {
|
|
noMore.value = true
|
|
}
|
|
} catch (e) {
|
|
console.error('获取案例列表失败', e)
|
|
}
|
|
loading.value = false
|
|
}
|
|
|
|
// 加载更多
|
|
const loadMore = () => {
|
|
if (!noMore.value && !loading.value) {
|
|
page.value++
|
|
fetchCaseList()
|
|
}
|
|
}
|
|
|
|
// 跳转详情
|
|
const goToDetail = (id : string) => {
|
|
uni.navigateTo({
|
|
url: `/pages/cases/detail?id=${id}`
|
|
})
|
|
}
|
|
|
|
onLoad(() => {
|
|
initCategories()
|
|
fetchCaseList()
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.page {
|
|
flex: 1;
|
|
background-color: #f5f5f5;
|
|
}
|
|
|
|
/* 分类栏 */
|
|
.category-bar {
|
|
background-color: #ffffff;
|
|
padding: 24rpx 0;
|
|
border-bottom-width: 1rpx;
|
|
border-bottom-style: solid;
|
|
border-bottom-color: #EBEEF5;
|
|
}
|
|
|
|
.category-scroll {
|
|
flex-direction: row;
|
|
}
|
|
.category-scroll ::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
.category-list {
|
|
flex-direction: row;
|
|
padding: 0 24rpx;
|
|
}
|
|
|
|
.category-item {
|
|
padding: 16rpx 32rpx;
|
|
margin-right: 16rpx;
|
|
border-radius: 999rpx;
|
|
background-color: #f5f5f5;
|
|
}
|
|
|
|
.category-active {
|
|
background-color: #D4A574;
|
|
}
|
|
|
|
.category-text {
|
|
font-size: 28rpx;
|
|
color: #606266;
|
|
}
|
|
|
|
.category-text-active {
|
|
color: #ffffff;
|
|
}
|
|
|
|
/* 案例列表 */
|
|
.case-scroll {
|
|
flex: 1;
|
|
}
|
|
|
|
.case-list {
|
|
padding: 24rpx;
|
|
}
|
|
|
|
/* 加载状态 */
|
|
.load-status {
|
|
padding: 32rpx 0;
|
|
align-items: center;
|
|
}
|
|
|
|
.load-text {
|
|
font-size: 26rpx;
|
|
color: #909399;
|
|
}
|
|
|
|
/* 空状态 */
|
|
.empty-state {
|
|
padding: 120rpx 0;
|
|
align-items: center;
|
|
}
|
|
|
|
.empty-icon {
|
|
font-size: 80rpx;
|
|
margin-bottom: 24rpx;
|
|
}
|
|
|
|
.empty-text {
|
|
font-size: 28rpx;
|
|
color: #909399;
|
|
}
|
|
|
|
/* 底部间距 */
|
|
.bottom-space {
|
|
height: 120rpx;
|
|
}
|
|
</style>
|