Files
hms/apps/miniprogram/src/pages/profile/index.tsx
iven 616e0a1539 feat(mp): 小程序功能完善 — 服务层扩展 + 页面优化
- 新增 actionInbox 服务层(待办事项列表/线程查询)
- consultation 服务扩展(会话详情/发送消息)
- 多页面代码优化(profile/messages/health/article)
- 新增 navigate 工具函数
2026-05-13 23:26:38 +08:00

191 lines
7.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { View, Text } from '@tarojs/components';
import Taro, { useDidShow } from '@tarojs/taro';
import { useAuthStore } from '../../stores/auth';
import { usePointsStore } from '../../stores/points';
import { useUIStore } from '../../stores/ui';
import { navigateToLogin } from '../../utils/navigate';
import './index.scss';
interface MenuItem {
label: string;
icon: string;
bg: string;
color: string;
path: string;
isSwitchTab?: boolean;
}
interface MenuGroup {
title: string;
items: MenuItem[];
}
const LOGGED_IN_GROUPS: MenuGroup[] = [
{
title: '健康管理',
items: [
{ label: '健康记录', icon: '健', bg: 'pri-l', color: 'pri', path: '/pages/pkg-profile/health-records/index' },
{ label: '我的报告', icon: '报', bg: 'acc-l', color: 'acc', path: '/pages/pkg-profile/reports/index' },
{ label: 'AI 分析', icon: '智', bg: 'pri-l', color: 'pri', path: '/pages/ai-report/list/index' },
{ label: '诊断记录', icon: '诊', bg: 'acc-l', color: 'acc', path: '/pages/pkg-profile/diagnoses/index' },
{ label: '用药记录', icon: '药', bg: 'pri-l', color: 'pri', path: '/pages/pkg-profile/medication/index' },
],
},
{
title: '就诊服务',
items: [
{ label: '我的预约', icon: '约', bg: 'pri-l', color: 'pri', path: '/pages/appointment/index' },
{ label: '我的随访', icon: '随', bg: 'acc-l', color: 'acc', path: '/pages/pkg-profile/followups/index' },
{ label: '在线咨询', icon: '问', bg: 'pri-l', color: 'pri', path: '/pages/consultation/index' },
],
},
{
title: '透析管理',
items: [
{ label: '透析记录', icon: '透', bg: 'pri-l', color: 'pri', path: '/pages/pkg-profile/dialysis-records/index' },
{ label: '透析处方', icon: '方', bg: 'acc-l', color: 'acc', path: '/pages/pkg-profile/dialysis-prescriptions/index' },
{ label: '知情同意', icon: '知', bg: 'pri-l', color: 'pri', path: '/pages/pkg-profile/consents/index' },
],
},
{
title: '生活服务',
items: [
{ label: '积分商城', icon: '礼', bg: 'pri-l', color: 'pri', path: '/pages/mall/index', isSwitchTab: true },
{ label: '线下活动', icon: '活', bg: 'acc-l', color: 'acc', path: '/pages/events/index' },
],
},
{
title: '账号',
items: [
{ label: '就诊人管理', icon: '家', bg: 'pri-l', color: 'pri', path: '/pages/pkg-profile/family/index' },
{ label: '长辈模式', icon: '老', bg: 'acc-l', color: 'acc', path: '/pages/pkg-profile/elder-mode/index' },
{ label: '设备同步', icon: '设', bg: 'surface-alt', color: 'tx3', path: '/pages/device-sync/index' },
{ label: '设置', icon: '齿', bg: 'surface-alt', color: 'tx3', path: '/pages/pkg-profile/settings/index' },
],
},
];
const GUEST_GROUPS: MenuGroup[] = [
{
title: '设置',
items: [
{ label: '长辈模式', icon: '老', bg: 'acc-l', color: 'acc', path: '/pages/pkg-profile/elder-mode/index' },
{ label: '设置', icon: '齿', bg: 'surface-alt', color: 'tx3', path: '/pages/pkg-profile/settings/index' },
],
},
];
export default function Profile() {
const { user, logout } = useAuthStore();
const { account: pointsAccount, checkinStatus: checkinInfo, refresh: refreshPoints } = usePointsStore();
const mode = useUIStore((s) => s.mode);
const modeClass = mode === 'elder' ? 'elder-mode' : '';
const isGuest = !user;
const groups = isGuest ? GUEST_GROUPS : LOGGED_IN_GROUPS;
useDidShow(() => {
if (!isGuest) refreshPoints();
});
const handleMenuClick = (item: MenuItem) => {
if (item.isSwitchTab) {
Taro.switchTab({ url: item.path });
} else {
Taro.navigateTo({ url: item.path });
}
};
const handleLogout = () => {
Taro.showModal({
title: '退出登录',
content: '确定要退出登录吗?',
}).then((res) => {
if (res.confirm) {
logout();
}
});
};
const displayName = user?.display_name || user?.username || (user?.phone ? `${user.phone.slice(-4)}` : '') || '用户';
const displayInitial = (user?.display_name || user?.username || '用').charAt(0);
return (
<View className={`profile-page ${modeClass}`}>
{/* 用户信息卡片 */}
{isGuest ? (
<View className='profile-user-card' onClick={navigateToLogin}>
<View className='profile-avatar profile-avatar--guest'>
<Text className='profile-avatar-char'>?</Text>
</View>
<View className='profile-user-info'>
<Text className='profile-name'></Text>
<Text className='profile-phone'></Text>
</View>
<Text className='profile-arrow'></Text>
</View>
) : (
<>
<View className='profile-user-card'>
<View className='profile-avatar'>
<Text className='profile-avatar-char'>{displayInitial}</Text>
</View>
<View className='profile-user-info'>
<Text className='profile-name'>{displayName}</Text>
<Text className='profile-phone'>
{user?.phone ? `${user.phone.slice(0, 3)}****${user.phone.slice(-4)}` : ''}
</Text>
</View>
<Text className='profile-arrow'></Text>
</View>
{/* 积分 + 打卡 */}
<View className='profile-stats-row'>
<View className='stat-card'>
<Text className='stat-value stat-pri'>{(pointsAccount?.balance ?? 0).toLocaleString()}</Text>
<Text className='stat-label'></Text>
</View>
<View className='stat-card'>
<Text className='stat-value stat-acc'>{checkinInfo?.consecutive_days ?? 0}<Text className='stat-unit'></Text></Text>
<Text className='stat-label'></Text>
</View>
</View>
</>
)}
{/* 分组菜单 */}
{groups.map((group) => (
<View className='menu-group' key={group.title}>
<Text className='menu-group-title'>{group.title}</Text>
<View className='menu-group-card'>
{group.items.map((item, idx) => (
<View
className='menu-item'
key={item.label}
onClick={() => handleMenuClick(item)}
>
<View className={`menu-icon menu-icon--${item.bg}`}>
<Text className={`menu-icon-text menu-icon-text--${item.color}`}>{item.icon}</Text>
</View>
<Text className='menu-label'>{item.label}</Text>
{idx < group.items.length - 1 && <View className='menu-divider' />}
<Text className='menu-arrow'></Text>
</View>
))}
</View>
</View>
))}
{/* 退出登录 / 登录 */}
{isGuest ? (
<View className='profile-logout' onClick={navigateToLogin}>
<Text className='logout-text logout-text--pri'></Text>
</View>
) : (
<View className='profile-logout' onClick={handleLogout}>
<Text className='logout-text'>退</Text>
</View>
)}
</View>
);
}