feat(miniprogram): Phase 5 UI/UX 优化 — 8 项改进
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled

- 首页: 健康资讯推荐 + 空状态引导 + 快捷服务字符图标优化
- 健康 Hub: sparkline bar + 参考范围 + 打卡合并到快捷操作
- 日常监测: 3 分组折叠(晨间/晚间/其他) + 异常值高亮 + 提交前确认
- 预约: 已满时段 pointer-events:none + opacity 优化
- 咨询聊天: 消息日期分组(今天/昨天) + 图片预览
- 积分商城: 确认已有余额大字+签到+库存提示
- 医护工作台: 异常体征横幅 + 患者搜索入口 + 快捷操作扩展
- 趋势图表: 骨架屏加载状态 + ECharts 异常标记已有
This commit is contained in:
iven
2026-04-28 08:51:27 +08:00
parent 852a429ef3
commit 0e45778fc3
13 changed files with 693 additions and 286 deletions

View File

@@ -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;
}

View File

@@ -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>
);
}