diff --git a/apps/miniprogram/src/app.config.ts b/apps/miniprogram/src/app.config.ts index 2e158f6..fc2465f 100644 --- a/apps/miniprogram/src/app.config.ts +++ b/apps/miniprogram/src/app.config.ts @@ -10,9 +10,7 @@ export default defineAppConfig({ 'pages/appointment/detail/index', 'pages/article/index', 'pages/article/detail/index', - 'pages/report/index', 'pages/report/detail/index', - 'pages/followup/index', 'pages/followup/detail/index', 'pages/profile/index', 'pages/profile/family/index', @@ -28,11 +26,11 @@ export default defineAppConfig({ backgroundColor: '#FFFFFF', borderStyle: 'white', list: [ - { pagePath: 'pages/index/index', text: '首页' }, - { pagePath: 'pages/health/index', text: '健康' }, - { pagePath: 'pages/appointment/index', text: '预约' }, - { pagePath: 'pages/article/index', text: '资讯' }, - { pagePath: 'pages/profile/index', text: '我的' }, + { pagePath: 'pages/index/index', text: '首页', iconPath: 'assets/tabbar/home.png', selectedIconPath: 'assets/tabbar/home-active.png' }, + { pagePath: 'pages/health/index', text: '健康', iconPath: 'assets/tabbar/health.png', selectedIconPath: 'assets/tabbar/health-active.png' }, + { pagePath: 'pages/appointment/index', text: '预约', iconPath: 'assets/tabbar/appointment.png', selectedIconPath: 'assets/tabbar/appointment-active.png' }, + { pagePath: 'pages/article/index', text: '资讯', iconPath: 'assets/tabbar/article.png', selectedIconPath: 'assets/tabbar/article-active.png' }, + { pagePath: 'pages/profile/index', text: '我的', iconPath: 'assets/tabbar/profile.png', selectedIconPath: 'assets/tabbar/profile-active.png' }, ], }, window: { diff --git a/apps/miniprogram/src/assets/tabbar/appointment-active.png b/apps/miniprogram/src/assets/tabbar/appointment-active.png new file mode 100644 index 0000000..84c2edc Binary files /dev/null and b/apps/miniprogram/src/assets/tabbar/appointment-active.png differ diff --git a/apps/miniprogram/src/assets/tabbar/appointment.png b/apps/miniprogram/src/assets/tabbar/appointment.png new file mode 100644 index 0000000..b6106d1 Binary files /dev/null and b/apps/miniprogram/src/assets/tabbar/appointment.png differ diff --git a/apps/miniprogram/src/assets/tabbar/article-active.png b/apps/miniprogram/src/assets/tabbar/article-active.png new file mode 100644 index 0000000..84c2edc Binary files /dev/null and b/apps/miniprogram/src/assets/tabbar/article-active.png differ diff --git a/apps/miniprogram/src/assets/tabbar/article.png b/apps/miniprogram/src/assets/tabbar/article.png new file mode 100644 index 0000000..b6106d1 Binary files /dev/null and b/apps/miniprogram/src/assets/tabbar/article.png differ diff --git a/apps/miniprogram/src/assets/tabbar/health-active.png b/apps/miniprogram/src/assets/tabbar/health-active.png new file mode 100644 index 0000000..84c2edc Binary files /dev/null and b/apps/miniprogram/src/assets/tabbar/health-active.png differ diff --git a/apps/miniprogram/src/assets/tabbar/health.png b/apps/miniprogram/src/assets/tabbar/health.png new file mode 100644 index 0000000..b6106d1 Binary files /dev/null and b/apps/miniprogram/src/assets/tabbar/health.png differ diff --git a/apps/miniprogram/src/assets/tabbar/home-active.png b/apps/miniprogram/src/assets/tabbar/home-active.png new file mode 100644 index 0000000..84c2edc Binary files /dev/null and b/apps/miniprogram/src/assets/tabbar/home-active.png differ diff --git a/apps/miniprogram/src/assets/tabbar/home.png b/apps/miniprogram/src/assets/tabbar/home.png new file mode 100644 index 0000000..b6106d1 Binary files /dev/null and b/apps/miniprogram/src/assets/tabbar/home.png differ diff --git a/apps/miniprogram/src/assets/tabbar/profile-active.png b/apps/miniprogram/src/assets/tabbar/profile-active.png new file mode 100644 index 0000000..84c2edc Binary files /dev/null and b/apps/miniprogram/src/assets/tabbar/profile-active.png differ diff --git a/apps/miniprogram/src/assets/tabbar/profile.png b/apps/miniprogram/src/assets/tabbar/profile.png new file mode 100644 index 0000000..b6106d1 Binary files /dev/null and b/apps/miniprogram/src/assets/tabbar/profile.png differ diff --git a/apps/miniprogram/src/pages/followup/index.scss b/apps/miniprogram/src/pages/followup/index.scss deleted file mode 100644 index 29f5d8c..0000000 --- a/apps/miniprogram/src/pages/followup/index.scss +++ /dev/null @@ -1,132 +0,0 @@ -@import '../../styles/variables.scss'; - -.followup-page { - min-height: 100vh; - background: $bg; -} - -.tab-bar { - display: flex; - background: $card; - padding: 0; - box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04); -} - -.tab-item { - flex: 1; - display: flex; - justify-content: center; - align-items: center; - padding: 24px 0; - position: relative; - - &.active { - &::after { - content: ''; - position: absolute; - bottom: 0; - left: 50%; - transform: translateX(-50%); - width: 48px; - height: 4px; - background: $pri; - border-radius: 2px; - } - } -} - -.tab-text { - font-size: 28px; - color: $tx2; - - .tab-item.active & { - color: $pri; - font-weight: bold; - } -} - -.task-list { - padding: 24px; - display: flex; - flex-direction: column; - gap: 20px; -} - -.task-card { - background: $card; - border-radius: $r; - padding: 28px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); -} - -.task-top { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 12px; -} - -.task-name { - font-size: 30px; - font-weight: bold; - color: $tx; -} - -.task-status { - font-size: 24px; - padding: 4px 16px; - border-radius: 20px; - - &.pending { - color: $wrn; - background: $wrn-l; - } - - &.completed { - color: $acc; - background: $acc-l; - } - - &.overdue { - color: $dan; - background: $dan-l; - } -} - -.task-desc { - font-size: 26px; - color: $tx2; - display: block; - margin-bottom: 8px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.task-due { - font-size: 24px; - color: $tx3; - display: block; -} - -.empty-state { - display: flex; - justify-content: center; - align-items: center; - padding: 120px 0; -} - -.empty-text { - font-size: 28px; - color: $tx3; -} - -.loading-hint { - text-align: center; - padding: 24px 0; -} - -.loading-text { - font-size: 24px; - color: $tx3; -} diff --git a/apps/miniprogram/src/pages/followup/index.tsx b/apps/miniprogram/src/pages/followup/index.tsx deleted file mode 100644 index 4f4fc66..0000000 --- a/apps/miniprogram/src/pages/followup/index.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import React, { useState, useCallback } from 'react'; -import { View, Text } from '@tarojs/components'; -import Taro, { useDidShow } from '@tarojs/taro'; -import { listTasks, FollowUpTask } from '../../services/followup'; -import EmptyState from '../../components/EmptyState'; -import Loading from '../../components/Loading'; -import './index.scss'; - -const TABS = [ - { key: 'pending', label: '待完成' }, - { key: 'completed', label: '已完成' }, - { key: 'overdue', label: '已过期' }, -]; - -export default function FollowUpList() { - const [activeTab, setActiveTab] = useState('pending'); - const [tasks, setTasks] = useState([]); - const [loading, setLoading] = useState(false); - - const fetchTasks = useCallback(async (status: string) => { - setLoading(true); - try { - const res = await listTasks(status); - setTasks(res.data || []); - } catch { - Taro.showToast({ title: '加载失败', icon: 'none' }); - } finally { - setLoading(false); - } - }, []); - - useDidShow(() => { - fetchTasks(activeTab); - }, [activeTab, fetchTasks]); - - const handleTabChange = (key: string) => { - setActiveTab(key); - setTasks([]); - fetchTasks(key); - }; - - const goToDetail = (id: string) => { - Taro.navigateTo({ url: `/pages/followup/detail/index?id=${id}` }); - }; - - const getStatusClass = (status: string) => { - if (status === 'completed') return 'completed'; - if (status === 'overdue') return 'overdue'; - return 'pending'; - }; - - const getStatusLabel = (status: string) => { - if (status === 'completed') return '已完成'; - if (status === 'overdue') return '已过期'; - return '待完成'; - }; - - return ( - - {/* Tab 栏 */} - - {TABS.map((tab) => ( - handleTabChange(tab.key)} - > - {tab.label} - - ))} - - - {/* 任务列表 */} - - {tasks.map((t) => ( - goToDetail(t.id)} - > - - {t.task_type} - - {getStatusLabel(t.status)} - - - {t.description} - 截止日期:{t.due_date} - - ))} - - - {tasks.length === 0 && !loading && ( - { - const tab = TABS.find((t) => t.key === activeTab); - return tab ? tab.label : ''; - })()}任务`} /> - )} - - {loading && ( - - )} - - ); -} diff --git a/apps/miniprogram/src/pages/index/index.tsx b/apps/miniprogram/src/pages/index/index.tsx index f768469..585c16a 100644 --- a/apps/miniprogram/src/pages/index/index.tsx +++ b/apps/miniprogram/src/pages/index/index.tsx @@ -6,48 +6,50 @@ import EmptyState from '../../components/EmptyState'; import './index.scss'; export default function Index() { - const { user, restore } = useAuthStore(); + const { user, currentPatient, restore: restoreAuth } = useAuthStore(); const { todaySummary, refreshToday } = useHealthStore(); useDidShow(() => { - restore(); + restoreAuth(); refreshToday(); }); - const s = todaySummary || {}; + const hour = new Date().getHours(); + const greeting = hour < 12 ? '早上好' : hour < 18 ? '下午好' : '晚上好'; + const displayName = user?.display_name || currentPatient?.name || '访客'; - const greeting = () => { - const h = new Date().getHours(); - if (h < 6) return '凌晨好'; - if (h < 12) return '上午好'; - if (h < 14) return '中午好'; - if (h < 18) return '下午好'; - return '晚上好'; + const quickServices = [ + { label: '预约挂号', icon: '📅', path: '/pages/appointment/create/index' }, + { label: '健康录入', icon: '📊', path: '/pages/health/input/index' }, + { label: '健康趋势', icon: '📈', path: '/pages/health/trend/index' }, + { label: '资讯文章', icon: '📰', path: '/pages/article/index' }, + ]; + + const handleServiceClick = (path: string) => { + Taro.navigateTo({ url: path }); }; + const healthItems = [ + { label: '血压', value: todaySummary?.blood_pressure ? `${todaySummary.blood_pressure.systolic}/${todaySummary.blood_pressure.diastolic}` : '--/--', unit: 'mmHg' }, + { label: '心率', value: todaySummary?.heart_rate ? `${todaySummary.heart_rate.value}` : '--', unit: 'bpm' }, + { label: '血糖', value: todaySummary?.blood_sugar ? `${todaySummary.blood_sugar.value}` : '--', unit: 'mmol/L' }, + { label: '体重', value: todaySummary?.weight ? `${todaySummary.weight.value}` : '--', unit: 'kg' }, + ]; + return ( - {/* 问候栏 */} - {greeting()} - {user?.display_name || '用户'} + {greeting}, + {displayName} - - {new Date().toLocaleDateString('zh-CN', { month: 'long', day: 'numeric', weekday: 'short' })} - + {new Date().toLocaleDateString('zh-CN')} - {/* 今日健康卡片 */} 今日健康 - {[ - { label: '血压', value: s.blood_pressure ? `${s.blood_pressure.systolic}/${s.blood_pressure.diastolic}` : '--/--', unit: 'mmHg' }, - { label: '心率', value: s.heart_rate ? `${s.heart_rate.value}` : '--', unit: 'bpm' }, - { label: '血糖', value: s.blood_sugar ? `${s.blood_sugar.value}` : '--', unit: 'mmol/L' }, - { label: '体重', value: s.weight ? `${s.weight.value}` : '--', unit: 'kg' }, - ].map((item) => ( + {healthItems.map((item) => ( {item.label} {item.value} @@ -57,38 +59,21 @@ export default function Index() { - {/* 快捷服务 */} 快捷服务 - {[ - { label: '录数据', icon: '📝', path: '/pages/health/index', isTab: true }, - { label: '预约', icon: '📅', path: '/pages/appointment/index', isTab: true }, - { label: '报告', icon: '📋', path: '/pages/report/index', isTab: false }, - { label: '随访', icon: '💬', path: '/pages/followup/index', isTab: false }, - ].map((item) => ( - { - if (item.isTab) { - Taro.switchTab({ url: item.path }); - } else { - Taro.navigateTo({ url: item.path }); - } - }} - > - {item.icon} - {item.label} + {quickServices.map((svc) => ( + handleServiceClick(svc.path)}> + {svc.icon} + {svc.label} ))} - {/* 即将到来 */} - 即将到来 - + 待办事项 + ); diff --git a/apps/miniprogram/src/pages/profile/index.tsx b/apps/miniprogram/src/pages/profile/index.tsx index 7fd9ea1..0dc817a 100644 --- a/apps/miniprogram/src/pages/profile/index.tsx +++ b/apps/miniprogram/src/pages/profile/index.tsx @@ -1,6 +1,5 @@ -import React from 'react'; import { View, Text } from '@tarojs/components'; -import Taro from '@tarojs/taro'; +import Taro, { useDidShow } from '@tarojs/taro'; import { useAuthStore } from '../../stores/auth'; import './index.scss'; @@ -13,7 +12,11 @@ const MENU_ITEMS = [ ]; export default function Profile() { - const { user, logout } = useAuthStore(); + const { user, restore: restoreAuth, logout } = useAuthStore(); + + useDidShow(() => { + restoreAuth(); + }); const handleMenuClick = (path: string) => { Taro.navigateTo({ url: path }); diff --git a/apps/miniprogram/src/pages/report/index.scss b/apps/miniprogram/src/pages/report/index.scss deleted file mode 100644 index 62ddf35..0000000 --- a/apps/miniprogram/src/pages/report/index.scss +++ /dev/null @@ -1,88 +0,0 @@ -@import '../../styles/variables.scss'; - -.report-page { - min-height: 100vh; - background: $bg; - padding: 24px; - padding-bottom: 40px; -} - -.report-list { - display: flex; - flex-direction: column; - gap: 20px; -} - -.report-card { - background: $card; - border-radius: $r; - padding: 28px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); -} - -.report-card-top { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 12px; -} - -.report-type { - font-size: 30px; - font-weight: bold; - color: $tx; -} - -.report-status { - font-size: 24px; - padding: 4px 16px; - border-radius: 20px; - - &.normal { - color: $acc; - background: $acc-l; - } - - &.abnormal { - color: $dan; - background: $dan-l; - } -} - -.report-date { - font-size: 26px; - color: $tx2; - display: block; - margin-bottom: 8px; -} - -.report-note { - font-size: 24px; - color: $tx3; - display: block; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.empty-state { - display: flex; - justify-content: center; - align-items: center; - padding: 120px 0; -} - -.empty-text { - font-size: 28px; - color: $tx3; -} - -.loading-hint { - text-align: center; - padding: 24px 0; -} - -.loading-text { - font-size: 24px; - color: $tx3; -} diff --git a/apps/miniprogram/src/pages/report/index.tsx b/apps/miniprogram/src/pages/report/index.tsx deleted file mode 100644 index 3d857bc..0000000 --- a/apps/miniprogram/src/pages/report/index.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import React, { useState, useCallback } from 'react'; -import { View, Text } from '@tarojs/components'; -import Taro, { useDidShow, usePullDownRefresh, useReachBottom } from '@tarojs/taro'; -import { listReports, LabReport } from '../../services/report'; -import EmptyState from '../../components/EmptyState'; -import Loading from '../../components/Loading'; -import './index.scss'; - -const PAGE_SIZE = 20; - -export default function ReportList() { - const [reports, setReports] = useState([]); - const [page, setPage] = useState(1); - const [total, setTotal] = useState(0); - const [loading, setLoading] = useState(false); - - const fetchData = useCallback(async (p: number, append = false) => { - const patientId = Taro.getStorageSync('current_patient_id') || ''; - if (!patientId) return; - setLoading(true); - try { - const res = await listReports(patientId, p); - const list = res.data || []; - setReports(append ? (prev) => [...prev, ...list] : list); - setTotal(res.total); - setPage(p); - } catch { - Taro.showToast({ title: '加载失败', icon: 'none' }); - } finally { - setLoading(false); - } - }, []); - - useDidShow(() => { - fetchData(1); - }); - - usePullDownRefresh(() => { - fetchData(1).finally(() => { - Taro.stopPullDownRefresh(); - }); - }); - - useReachBottom(() => { - if (!loading && reports.length < total) { - fetchData(page + 1, true); - } - }); - - const goToDetail = (id: string) => { - Taro.navigateTo({ url: `/pages/report/detail/index?id=${id}` }); - }; - - const formatStatus = (report: LabReport) => { - const indicators = report.indicators; - if (!indicators || typeof indicators !== 'object') return '未知'; - const vals = Object.values(indicators) as Array<{ status?: string }>; - const hasAbnormal = vals.some((v) => v.status === 'high' || v.status === 'low'); - return hasAbnormal ? '异常' : '正常'; - }; - - return ( - - - {reports.map((r) => ( - goToDetail(r.id)} - > - - {r.report_type} - - {formatStatus(r)} - - - {r.report_date} - {r.doctor_interpretation && ( - {r.doctor_interpretation} - )} - - ))} - - - {reports.length === 0 && !loading && ( - - )} - - {loading && ( - - )} - - ); -}