refactor(mp): 迁移随访列表页 — 使用统一组件库 PageShell/ContentCard/StatusTag/LoadingCard/SearchSection
This commit is contained in:
@@ -1,13 +1,12 @@
|
|||||||
@import '../../../styles/variables.scss';
|
@import '../../../styles/variables.scss';
|
||||||
@import '../../../styles/mixins.scss';
|
|
||||||
|
|
||||||
.followup-page {
|
// PageShell 已接管:min-height, background, padding
|
||||||
min-height: 100vh;
|
// SearchSection 已接管:标签筛选栏
|
||||||
background: $bg;
|
// ContentCard 已接管:task-card 背景/圆角/阴影/触摸反馈
|
||||||
}
|
// StatusTag 已接管:任务状态标签
|
||||||
|
|
||||||
.task-count {
|
.task-count {
|
||||||
padding: 20px 28px;
|
margin-bottom: 16px;
|
||||||
|
|
||||||
text {
|
text {
|
||||||
font-size: var(--tk-font-h2);
|
font-size: var(--tk-font-h2);
|
||||||
@@ -16,56 +15,37 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.task-list {
|
.task-list {
|
||||||
padding: 0 24px 120px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 16px;
|
gap: var(--tk-gap-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-card {
|
.task-card__header {
|
||||||
background: $card;
|
display: flex;
|
||||||
border-radius: $r-lg;
|
justify-content: space-between;
|
||||||
padding: 28px;
|
align-items: center;
|
||||||
box-shadow: $shadow-sm;
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
&:active {
|
|
||||||
background: $bd-l;
|
.task-card__type {
|
||||||
}
|
font-size: var(--tk-font-body-lg);
|
||||||
|
font-weight: 600;
|
||||||
&__header {
|
color: $tx;
|
||||||
display: flex;
|
}
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
.task-card__patient {
|
||||||
margin-bottom: 12px;
|
font-size: var(--tk-font-h1);
|
||||||
}
|
color: $tx2;
|
||||||
|
display: block;
|
||||||
&__type {
|
margin-bottom: 8px;
|
||||||
font-family: 'Georgia', 'Times New Roman', serif;
|
}
|
||||||
font-size: var(--tk-font-body-lg);
|
|
||||||
font-weight: 600;
|
.task-card__footer {
|
||||||
color: $tx;
|
display: flex;
|
||||||
}
|
justify-content: space-between;
|
||||||
|
}
|
||||||
&__status {
|
|
||||||
@include tag(transparent, $tx2);
|
.task-card__date {
|
||||||
font-size: var(--tk-font-body);
|
font-size: var(--tk-font-h2);
|
||||||
font-weight: 500;
|
color: $tx3;
|
||||||
}
|
|
||||||
|
|
||||||
&__patient {
|
|
||||||
font-size: var(--tk-font-h1);
|
|
||||||
color: $tx2;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__footer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__date {
|
|
||||||
font-size: var(--tk-font-h2);
|
|
||||||
color: $tx3;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||||
import { View, Text, ScrollView } from '@tarojs/components';
|
import { View, Text } from '@tarojs/components';
|
||||||
import Taro, { useRouter } from '@tarojs/taro';
|
import Taro, { useRouter } from '@tarojs/taro';
|
||||||
import { usePageData } from '@/hooks/usePageData';
|
import { usePageData } from '@/hooks/usePageData';
|
||||||
import { listFollowUpTasks, type FollowUpTask } from '@/services/doctor/followup';
|
import { listFollowUpTasks, type FollowUpTask } from '@/services/doctor/followup';
|
||||||
import Loading from '@/components/Loading';
|
import PageShell from '@/components/ui/PageShell';
|
||||||
|
import ContentCard from '@/components/ui/ContentCard';
|
||||||
|
import StatusTag from '@/components/ui/StatusTag';
|
||||||
|
import LoadingCard from '@/components/ui/LoadingCard';
|
||||||
|
import SearchSection from '@/components/patterns/SearchSection';
|
||||||
import ErrorState from '@/components/ErrorState';
|
import ErrorState from '@/components/ErrorState';
|
||||||
import EmptyState from '@/components/EmptyState';
|
import EmptyState from '@/components/EmptyState';
|
||||||
import { useElderClass } from '../../../hooks/useElderClass';
|
import { useElderClass } from '../../../hooks/useElderClass';
|
||||||
import { getStatusInlineStyle, getStatusLabel } from '@/utils/statusTag';
|
|
||||||
import SegmentTabs from '@/components/SegmentTabs';
|
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
|
|
||||||
const TABS = [
|
const TABS = [
|
||||||
@@ -19,6 +21,13 @@ const TABS = [
|
|||||||
{ key: 'overdue', label: '已逾期' },
|
{ key: 'overdue', label: '已逾期' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const STATUS_COLOR_MAP: Record<string, 'warning' | 'info' | 'success' | 'error'> = {
|
||||||
|
pending: 'warning',
|
||||||
|
in_progress: 'info',
|
||||||
|
completed: 'success',
|
||||||
|
overdue: 'error',
|
||||||
|
};
|
||||||
|
|
||||||
export default function FollowUpList() {
|
export default function FollowUpList() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const patientId = router.params.patientId || '';
|
const patientId = router.params.patientId || '';
|
||||||
@@ -52,7 +61,6 @@ export default function FollowUpList() {
|
|||||||
|
|
||||||
const { trigger } = usePageData(loadTasks);
|
const { trigger } = usePageData(loadTasks);
|
||||||
|
|
||||||
// tab/patientId 变化时重新加载(跳过首次 mount,由 usePageData 的 useDidShow 处理)
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (mountedRef.current) {
|
if (mountedRef.current) {
|
||||||
trigger();
|
trigger();
|
||||||
@@ -74,43 +82,48 @@ export default function FollowUpList() {
|
|||||||
return map[type] || type;
|
return map[type] || type;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (loading && tasks.length === 0) return <Loading />;
|
if (loading && tasks.length === 0) return <LoadingCard count={3} />;
|
||||||
if (error) return <ErrorState onRetry={loadTasks} />;
|
if (error) return <ErrorState onRetry={loadTasks} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView scrollY className={`followup-page ${modeClass}`}>
|
<PageShell safeBottom className={modeClass}>
|
||||||
<SegmentTabs tabs={TABS} activeKey={activeTab} onChange={(key) => setActiveTab(key)} variant="underline" />
|
<SearchSection
|
||||||
|
value=""
|
||||||
|
onChange={() => {}}
|
||||||
|
filters={TABS}
|
||||||
|
activeFilter={activeTab}
|
||||||
|
onFilterChange={(key) => setActiveTab(key)}
|
||||||
|
/>
|
||||||
|
|
||||||
<View className='task-count'>
|
<View className="task-count">
|
||||||
<Text>共 {total} 项任务</Text>
|
<Text>共 {total} 项任务</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{tasks.length === 0 ? (
|
{tasks.length === 0 ? (
|
||||||
<EmptyState text='暂无随访任务' />
|
<EmptyState text="暂无随访任务" />
|
||||||
) : (
|
) : (
|
||||||
<View className='task-list'>
|
<View className="task-list">
|
||||||
{tasks.map((task) => {
|
{tasks.map((task) => (
|
||||||
return (
|
<ContentCard
|
||||||
<View
|
key={task.id}
|
||||||
key={task.id}
|
onPress={() => Taro.navigateTo({ url: `/pages/pkg-doctor-core/followup/detail/index?id=${task.id}` })}
|
||||||
className='task-card'
|
>
|
||||||
onClick={() => Taro.navigateTo({ url: `/pages/pkg-doctor-core/followup/detail/index?id=${task.id}` })}
|
<View className="task-card__header">
|
||||||
>
|
<Text className="task-card__type">{getTypeLabel(task.follow_up_type)}</Text>
|
||||||
<View className='task-card__header'>
|
<StatusTag
|
||||||
<Text className='task-card__type'>{getTypeLabel(task.follow_up_type)}</Text>
|
status={task.status}
|
||||||
<View className='task-card__status' style={getStatusInlineStyle(task.status)}>
|
colorMap={STATUS_COLOR_MAP}
|
||||||
<Text>{getStatusLabel(task.status)}</Text>
|
size="sm"
|
||||||
</View>
|
/>
|
||||||
</View>
|
|
||||||
<Text className='task-card__patient'>{task.patient_name || '未知患者'}</Text>
|
|
||||||
<View className='task-card__footer'>
|
|
||||||
<Text className='task-card__date'>计划日期: {formatDate(task.planned_date)}</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
);
|
<Text className="task-card__patient">{task.patient_name || '未知患者'}</Text>
|
||||||
})}
|
<View className="task-card__footer">
|
||||||
|
<Text className="task-card__date">计划日期: {formatDate(task.planned_date)}</Text>
|
||||||
|
</View>
|
||||||
|
</ContentCard>
|
||||||
|
))}
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</ScrollView>
|
</PageShell>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user