refactor(mp): 迁移文章列表页 — 使用统一组件库
- PageShell 替代手写 min-height/bg/padding - ContentCard 替代手写 article-card 卡片样式 - LoadingCard 替代初始加载态 - 精简 SCSS 删除已接管样式,保留分类筛选/卡片内容布局 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,11 @@
|
||||
@import '../../styles/variables.scss';
|
||||
@import '../../styles/mixins.scss';
|
||||
|
||||
.article-page {
|
||||
min-height: 100vh;
|
||||
background: $bg;
|
||||
padding: 24px;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
// PageShell 已接管:min-height, background, padding
|
||||
// ContentCard 已接管:article-card 背景/圆角/阴影/触摸反馈
|
||||
// LoadingCard 已接管:初始加载骨架屏
|
||||
// EmptyState 已接管:空状态样式
|
||||
|
||||
/* ─── 分类筛选滚动条(页面特有) ─── */
|
||||
.article-categories {
|
||||
white-space: nowrap;
|
||||
margin-bottom: 24px;
|
||||
@@ -31,20 +29,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── 文章列表布局 ─── */
|
||||
.article-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.article-card {
|
||||
display: flex;
|
||||
background: $card;
|
||||
border-radius: $r;
|
||||
padding: 28px;
|
||||
box-shadow: $shadow-sm;
|
||||
}
|
||||
|
||||
/* ─── 文章卡片内容(ContentCard 已接管外层卡片样式) ─── */
|
||||
.article-card-body {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
@@ -107,25 +99,3 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 120px 0;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: var(--tk-font-body-lg);
|
||||
color: var(--tk-text-secondary);
|
||||
}
|
||||
|
||||
.loading-hint {
|
||||
text-align: center;
|
||||
padding: 24px 0;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: var(--tk-font-h2);
|
||||
color: var(--tk-text-secondary);
|
||||
}
|
||||
|
||||
@@ -3,9 +3,12 @@ import { View, Text, Image, ScrollView } from '@tarojs/components';
|
||||
import Taro, { useReachBottom } from '@tarojs/taro';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { listArticles, listCategories, Article, ArticleCategory } from '../../services/article';
|
||||
import EmptyState from '../../components/EmptyState';
|
||||
import ErrorState from '../../components/ErrorState';
|
||||
import Loading from '../../components/Loading';
|
||||
import PageShell from '@/components/ui/PageShell';
|
||||
import ContentCard from '@/components/ui/ContentCard';
|
||||
import LoadingCard from '@/components/ui/LoadingCard';
|
||||
import EmptyState from '@/components/EmptyState';
|
||||
import ErrorState from '@/components/ErrorState';
|
||||
import Loading from '@/components/Loading';
|
||||
import { useElderClass } from '../../hooks/useElderClass';
|
||||
import './index.scss';
|
||||
|
||||
@@ -73,8 +76,12 @@ export default function ArticleList() {
|
||||
Taro.navigateTo({ url: `/pages/article/detail/index?id=${id}` });
|
||||
};
|
||||
|
||||
if (!loading && articles.length === 0 && !error && !categories.length) {
|
||||
return <LoadingCard count={3} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<View className={`article-page ${modeClass}`}>
|
||||
<PageShell safeBottom className={modeClass}>
|
||||
{/* 分类筛选 */}
|
||||
{categories.length > 0 && (
|
||||
<ScrollView scrollX className='article-categories'>
|
||||
@@ -96,47 +103,44 @@ export default function ArticleList() {
|
||||
</ScrollView>
|
||||
)}
|
||||
|
||||
<View className='article-list'>
|
||||
{error ? (
|
||||
<ErrorState onRetry={() => fetchData(1, false, null)} />
|
||||
) : articles.map((a) => (
|
||||
<View
|
||||
className='article-card'
|
||||
key={a.id}
|
||||
onClick={() => goToDetail(a.id)}
|
||||
>
|
||||
<View className='article-card-body'>
|
||||
<Text className='article-card-title'>{a.title}</Text>
|
||||
{a.summary && (
|
||||
<Text className='article-card-summary'>{a.summary}</Text>
|
||||
)}
|
||||
<View className='article-card-meta'>
|
||||
{(a.category_name || a.category) && (
|
||||
<Text className='article-card-tag'>{a.category_name || a.category}</Text>
|
||||
)}
|
||||
{a.published_at && (
|
||||
<Text className='article-card-date'>
|
||||
{a.published_at.slice(0, 10)}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
{a.cover_image && (
|
||||
<View className='article-card-cover'>
|
||||
<Image className='cover-img' src={a.cover_image} mode='aspectFill' lazyLoad />
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{articles.length === 0 && !loading && (
|
||||
{error ? (
|
||||
<ErrorState onRetry={() => fetchData(1, false, null)} />
|
||||
) : articles.length === 0 && !loading ? (
|
||||
<EmptyState text='暂无资讯文章' />
|
||||
) : (
|
||||
<View className='article-list'>
|
||||
{articles.map((a) => (
|
||||
<ContentCard
|
||||
key={a.id}
|
||||
onPress={() => goToDetail(a.id)}
|
||||
>
|
||||
<View className='article-card-body'>
|
||||
<Text className='article-card-title'>{a.title}</Text>
|
||||
{a.summary && (
|
||||
<Text className='article-card-summary'>{a.summary}</Text>
|
||||
)}
|
||||
<View className='article-card-meta'>
|
||||
{(a.category_name || a.category) && (
|
||||
<Text className='article-card-tag'>{a.category_name || a.category}</Text>
|
||||
)}
|
||||
{a.published_at && (
|
||||
<Text className='article-card-date'>
|
||||
{a.published_at.slice(0, 10)}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
{a.cover_image && (
|
||||
<View className='article-card-cover'>
|
||||
<Image className='cover-img' src={a.cover_image} mode='aspectFill' lazyLoad />
|
||||
</View>
|
||||
)}
|
||||
</ContentCard>
|
||||
))}
|
||||
</View>
|
||||
)}
|
||||
|
||||
{loading && (
|
||||
<Loading />
|
||||
)}
|
||||
</View>
|
||||
{loading && <Loading />}
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user