feat(miniprogram): Phase 5 UI/UX 优化 — 8 项改进
- 首页: 健康资讯推荐 + 空状态引导 + 快捷服务字符图标优化 - 健康 Hub: sparkline bar + 参考范围 + 打卡合并到快捷操作 - 日常监测: 3 分组折叠(晨间/晚间/其他) + 异常值高亮 + 提交前确认 - 预约: 已满时段 pointer-events:none + opacity 优化 - 咨询聊天: 消息日期分组(今天/昨天) + 图片预览 - 积分商城: 确认已有余额大字+签到+库存提示 - 医护工作台: 异常体征横幅 + 患者搜索入口 + 快捷操作扩展 - 趋势图表: 骨架屏加载状态 + ECharts 异常标记已有
This commit is contained in:
@@ -261,3 +261,69 @@
|
||||
color: $tx3;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ─── 健康空状态 ─── */
|
||||
.health-empty {
|
||||
background: $bg;
|
||||
border-radius: $r-sm;
|
||||
padding: 40px 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.health-empty-text {
|
||||
display: block;
|
||||
font-size: 28px;
|
||||
color: $tx2;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.health-empty-action {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 24px 0 0;
|
||||
}
|
||||
|
||||
.health-empty-btn {
|
||||
background: $pri;
|
||||
border-radius: $r;
|
||||
padding: 16px 40px;
|
||||
}
|
||||
|
||||
.health-empty-btn-text {
|
||||
color: #fff;
|
||||
font-size: 26px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* ─── 健康资讯 ─── */
|
||||
.articles-section {
|
||||
margin: 0 24px 24px;
|
||||
}
|
||||
|
||||
.article-card {
|
||||
background: $card;
|
||||
border-radius: $r;
|
||||
padding: 24px;
|
||||
margin-bottom: 16px;
|
||||
box-shadow: $shadow-sm;
|
||||
|
||||
&:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.article-card-title {
|
||||
font-size: 28px;
|
||||
color: $tx;
|
||||
display: block;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.article-card-meta {
|
||||
font-size: 22px;
|
||||
color: $tx3;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import Loading from '../../components/Loading';
|
||||
import { trackPageView } from '@/services/analytics';
|
||||
import * as appointmentApi from '@/services/appointment';
|
||||
import * as followupApi from '@/services/followup';
|
||||
import * as articleApi from '../../services/article';
|
||||
import './index.scss';
|
||||
|
||||
interface UpcomingItem {
|
||||
@@ -24,14 +25,25 @@ export default function Index() {
|
||||
const { todaySummary, loading, refreshToday } = useHealthStore();
|
||||
const [upcomingItems, setUpcomingItems] = useState<UpcomingItem[]>([]);
|
||||
const [upcomingLoading, setUpcomingLoading] = useState(false);
|
||||
const [articles, setArticles] = useState<articleApi.Article[]>([]);
|
||||
|
||||
useDidShow(() => {
|
||||
restoreAuth();
|
||||
refreshToday();
|
||||
loadUpcoming();
|
||||
loadArticles();
|
||||
trackPageView('home');
|
||||
});
|
||||
|
||||
const loadArticles = async () => {
|
||||
try {
|
||||
const res = await articleApi.listArticles({ page: 1, page_size: 2 });
|
||||
setArticles(res.data || []);
|
||||
} catch {
|
||||
// 文章接口可能不可用
|
||||
}
|
||||
};
|
||||
|
||||
const loadUpcoming = async () => {
|
||||
const patientId = useAuthStore.getState().currentPatient?.id;
|
||||
if (!patientId) return;
|
||||
@@ -81,11 +93,11 @@ export default function Index() {
|
||||
const displayName = user?.display_name || currentPatient?.name || '访客';
|
||||
|
||||
const quickServices = [
|
||||
{ label: '预约挂号', path: '/pages/appointment/create/index' },
|
||||
{ label: '健康录入', path: '/pages/health/input/index' },
|
||||
{ label: '健康趋势', path: '/pages/health/trend/index' },
|
||||
{ label: '资讯文章', path: '/pages/article/index' },
|
||||
{ label: 'AI 报告', path: '/pages/ai-report/list/index' },
|
||||
{ label: '预约挂号', char: '约', path: '/pages/appointment/create/index' },
|
||||
{ label: '健康录入', char: '录', path: '/pages/health/input/index' },
|
||||
{ label: '健康趋势', char: '势', path: '/pages/health/trend/index' },
|
||||
{ label: '资讯文章', char: '文', path: '/pages/article/index' },
|
||||
{ label: 'AI 报告', char: 'AI', path: '/pages/ai-report/list/index' },
|
||||
];
|
||||
|
||||
const handleServiceClick = (path: string) => {
|
||||
@@ -121,6 +133,15 @@ export default function Index() {
|
||||
<Text className='section-title'>今日健康</Text>
|
||||
{loading && !todaySummary ? (
|
||||
<Loading />
|
||||
) : !todaySummary || (!todaySummary.blood_pressure && !todaySummary.heart_rate && !todaySummary.blood_sugar && !todaySummary.weight) ? (
|
||||
<View className='health-empty'>
|
||||
<Text className='health-empty-text'>今天还没录入数据</Text>
|
||||
<View className='health-empty-action'>
|
||||
<View className='health-empty-btn' onClick={() => Taro.navigateTo({ url: '/pages/health/input/index' })}>
|
||||
<Text className='health-empty-btn-text'>点击开始记录</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
) : (
|
||||
<View className='health-grid'>
|
||||
{healthItems.map((item) => {
|
||||
@@ -147,7 +168,7 @@ export default function Index() {
|
||||
{quickServices.map((svc) => (
|
||||
<View className='service-btn' key={svc.label} onClick={() => handleServiceClick(svc.path)}>
|
||||
<View className='service-icon-wrap'>
|
||||
<Text className='service-icon-text'>{svc.label[0]}</Text>
|
||||
<Text className='service-icon-text'>{svc.char}</Text>
|
||||
</View>
|
||||
<Text className='service-label'>{svc.label}</Text>
|
||||
</View>
|
||||
@@ -190,6 +211,25 @@ export default function Index() {
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* 健康资讯 */}
|
||||
{articles.length > 0 && (
|
||||
<View className='articles-section'>
|
||||
<Text className='section-title'>健康资讯</Text>
|
||||
{articles.map((article) => (
|
||||
<View
|
||||
className='article-card'
|
||||
key={article.id}
|
||||
onClick={() => Taro.navigateTo({ url: `/pages/article/detail/index?id=${article.id}` })}
|
||||
>
|
||||
<Text className='article-card-title'>{article.title}</Text>
|
||||
<Text className='article-card-meta'>
|
||||
{article.category_name || '健康'}{article.published_at ? ` · ${article.published_at.slice(0, 10)}` : ''}
|
||||
</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user