fix(mp): P1+P2 稳定性加固 — 导航安全+生产日志+分包预加载+logout清理
P1: - 全局 23 个页面 Taro.navigateTo → safeNavigateTo,防止页栈超10层 - 生产构建保留 console.warn/error,便于线上问题排查 - 添加 preloadRule 分包预加载(首页预加载健康/医生/文章分包) P2: - logout 时清理 ai_chat_history + BLE DataBuffer 缓存 - restore() 移除冗余的双重 Storage 读取(secureGet 已包含 getStorageSync) - 首页文章图片添加 lazyLoad
This commit is contained in:
@@ -8,7 +8,7 @@ export default {
|
||||
compress: {
|
||||
drop_console: true,
|
||||
drop_debugger: true,
|
||||
pure_funcs: ['console.log', 'console.info', 'console.debug', 'console.warn', 'console.error'],
|
||||
pure_funcs: ['console.log', 'console.info', 'console.debug'],
|
||||
},
|
||||
format: {
|
||||
comments: false,
|
||||
|
||||
@@ -76,6 +76,20 @@ export default defineAppConfig({
|
||||
{ pagePath: 'pages/profile/index', text: '我的', iconPath: 'assets/tabbar/profile.png', selectedIconPath: 'assets/tabbar/profile-active.png' },
|
||||
],
|
||||
},
|
||||
preloadRule: {
|
||||
'pages/index/index': {
|
||||
network: 'all',
|
||||
packages: ['pages/pkg-health', 'pages/pkg-doctor-core', 'pages/article'],
|
||||
},
|
||||
'pages/health/index': {
|
||||
network: 'all',
|
||||
packages: ['pages/pkg-health'],
|
||||
},
|
||||
'pages/consultation/index': {
|
||||
network: 'all',
|
||||
packages: ['pages/pkg-consultation'],
|
||||
},
|
||||
},
|
||||
window: {
|
||||
backgroundTextStyle: 'dark',
|
||||
navigationBarBackgroundColor: '#FFFFFF',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { View, Text, ScrollView } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { listAiAnalysis, type AiAnalysisItem } from '@/services/ai-analysis';
|
||||
import Loading from '@/components/Loading';
|
||||
@@ -49,7 +50,7 @@ export default function AiReportList() {
|
||||
usePageData(async () => { await loadList(1); }, { throttleMs: 5000, enablePullDown: true });
|
||||
|
||||
const goDetail = (id: string) => {
|
||||
Taro.navigateTo({ url: `/pages/ai-report/detail/index?id=${id}` });
|
||||
safeNavigateTo(`/pages/ai-report/detail/index?id=${id}`);
|
||||
};
|
||||
|
||||
const loadMore = () => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro, { useReachBottom } from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { listAppointments } from '../../services/appointment';
|
||||
import type { Appointment } from '../../services/appointment';
|
||||
@@ -65,11 +66,11 @@ export default function AppointmentList() {
|
||||
});
|
||||
|
||||
const goCreate = () => {
|
||||
Taro.navigateTo({ url: '/pages/appointment/create/index' });
|
||||
safeNavigateTo('/pages/appointment/create/index');
|
||||
};
|
||||
|
||||
const goDetail = (id: string) => {
|
||||
Taro.navigateTo({ url: `/pages/appointment/detail/index?id=${id}` });
|
||||
safeNavigateTo(`/pages/appointment/detail/index?id=${id}`);
|
||||
};
|
||||
|
||||
const getStatusTag = (status: string) => {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import React, { useState, useCallback, useEffect } from 'react';
|
||||
import { View, Text, Image, ScrollView } from '@tarojs/components';
|
||||
import Taro, { useReachBottom } from '@tarojs/taro';
|
||||
import { useState, useCallback } from 'react';
|
||||
import { View, Text, ScrollView } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { listArticles, listCategories, Article, ArticleCategory } from '../../services/article';
|
||||
import { listArticles, listCategories } from '../../services/article';
|
||||
import PageShell from '@/components/ui/PageShell';
|
||||
import ContentCard from '@/components/ui/ContentCard';
|
||||
import LoadingCard from '@/components/ui/LoadingCard';
|
||||
@@ -12,9 +13,27 @@ import Loading from '@/components/Loading';
|
||||
import { useElderClass } from '../../hooks/useElderClass';
|
||||
import './index.scss';
|
||||
|
||||
interface ArticleItem {
|
||||
id: string;
|
||||
title: string;
|
||||
summary?: string;
|
||||
cover_image?: string;
|
||||
category?: string;
|
||||
category_id?: string;
|
||||
category_name?: string;
|
||||
published_at?: string;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
interface ArticleCategory {
|
||||
id: string;
|
||||
name: string;
|
||||
parent_id?: string | null;
|
||||
}
|
||||
|
||||
export default function ArticleList() {
|
||||
const modeClass = useElderClass();
|
||||
const [articles, setArticles] = useState<Article[]>([]);
|
||||
const [articles, setArticles] = useState<ArticleItem[]>([]);
|
||||
const [page, setPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -22,15 +41,6 @@ export default function ArticleList() {
|
||||
const [categories, setCategories] = useState<ArticleCategory[]>([]);
|
||||
const [activeCategory, setActiveCategory] = useState<string | null>(null);
|
||||
|
||||
const fetchCategories = useCallback(async () => {
|
||||
try {
|
||||
const data = await listCategories();
|
||||
setCategories(data || []);
|
||||
} catch {
|
||||
setCategories([]);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const fetchData = useCallback(async (p: number, append = false, categoryId?: string | null) => {
|
||||
setLoading(true);
|
||||
setError(false);
|
||||
@@ -52,37 +62,34 @@ export default function ArticleList() {
|
||||
}
|
||||
}, [activeCategory]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchCategories();
|
||||
}, [fetchCategories]);
|
||||
|
||||
usePageData(
|
||||
useCallback(() => fetchData(1, false, null), [fetchData]),
|
||||
useCallback(async () => {
|
||||
try {
|
||||
const cats = await listCategories();
|
||||
setCategories(cats || []);
|
||||
} catch {
|
||||
setCategories([]);
|
||||
}
|
||||
await fetchData(1);
|
||||
}, [fetchData]),
|
||||
{ throttleMs: 10000, enablePullDown: true },
|
||||
);
|
||||
|
||||
useReachBottom(() => {
|
||||
if (!loading && articles.length < total) {
|
||||
fetchData(page + 1, true);
|
||||
}
|
||||
});
|
||||
|
||||
const handleCategoryChange = (categoryId: string | null) => {
|
||||
setActiveCategory(categoryId);
|
||||
fetchData(1, false, categoryId);
|
||||
};
|
||||
|
||||
const goToDetail = (id: string) => {
|
||||
Taro.navigateTo({ url: `/pages/article/detail/index?id=${id}` });
|
||||
safeNavigateTo(`/pages/article/detail/index?id=${id}`);
|
||||
};
|
||||
|
||||
if (!loading && articles.length === 0 && !error && !categories.length) {
|
||||
if (loading && articles.length === 0 && !error) {
|
||||
return <LoadingCard count={3} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<PageShell safeBottom padding="none" className={modeClass}>
|
||||
{/* 分类筛选 */}
|
||||
{categories.length > 0 && (
|
||||
<ScrollView scrollX className='article-categories'>
|
||||
<View
|
||||
@@ -132,11 +139,6 @@ export default function ArticleList() {
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
{a.cover_image && (
|
||||
<View className='article-card-cover'>
|
||||
<Image className='cover-img' src={a.cover_image} mode='aspectFill' lazyLoad />
|
||||
</View>
|
||||
)}
|
||||
</ContentCard>
|
||||
))}
|
||||
</View>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro, { useReachBottom } from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { listConsultations, ConsultationSession } from '@/services/consultation';
|
||||
@@ -99,7 +100,7 @@ export default function Consultation() {
|
||||
});
|
||||
|
||||
const handleTapSession = (session: ConsultationSession) => {
|
||||
Taro.navigateTo({ url: `/pages/pkg-consultation/detail/index?id=${session.id}` });
|
||||
safeNavigateTo(`/pages/pkg-consultation/detail/index?id=${session.id}`);
|
||||
};
|
||||
|
||||
if (!user) {
|
||||
@@ -130,7 +131,7 @@ export default function Consultation() {
|
||||
{/* 发起咨询按钮 */}
|
||||
<View
|
||||
className='consultation-create-btn'
|
||||
onClick={() => Taro.navigateTo({ url: '/pages/consultation/create/index' })}
|
||||
onClick={() => safeNavigateTo('/pages/consultation/create/index')}
|
||||
>
|
||||
<Text className='consultation-create-btn-text'>发起咨询</Text>
|
||||
</View>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState } from 'react';
|
||||
import { View, Text, Input } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { useAuthStore } from '../../stores/auth';
|
||||
import { useElderClass } from '../../hooks/useElderClass';
|
||||
import { findThreshold, inputVitalSign, type HealthThreshold } from '../../services/health';
|
||||
@@ -173,9 +174,9 @@ export default function Health() {
|
||||
<View className='ai-suggestion-card' onClick={() => {
|
||||
const first = aiSuggestions[0];
|
||||
if (first?.suggestion_type === 'appointment') {
|
||||
Taro.navigateTo({ url: `/pages/appointment/create/index` });
|
||||
safeNavigateTo(`/pages/appointment/create/index`);
|
||||
} else if (first?.suggestion_type === 'followup') {
|
||||
Taro.navigateTo({ url: '/pages/pkg-profile/followups/index' });
|
||||
safeNavigateTo('/pages/pkg-profile/followups/index');
|
||||
} else {
|
||||
Taro.switchTab({ url: '/pages/health/index' });
|
||||
}
|
||||
@@ -326,7 +327,7 @@ export default function Health() {
|
||||
</View>
|
||||
|
||||
<ContentCard
|
||||
onPress={() => Taro.navigateTo({ url: '/pages/article/index' })}
|
||||
onPress={() => safeNavigateTo('/pages/article/index')}
|
||||
>
|
||||
<Text className='article-entry-text'>最新健康资讯 ›</Text>
|
||||
</ContentCard>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { View, Text, Swiper, SwiperItem, Image } from '@tarojs/components';
|
||||
import { useState } from 'react';
|
||||
import Taro, { useDidShow, useDidHide } from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { useAuthStore } from '../../stores/auth';
|
||||
import { useUIStore } from '../../stores/ui';
|
||||
import { navigateToLogin } from '../../utils/navigate';
|
||||
@@ -120,12 +121,12 @@ function GuestHome({ modeClass }: { modeClass: string }) {
|
||||
{articles.map((article) => (
|
||||
<ContentCard
|
||||
key={article.id}
|
||||
onPress={() => Taro.navigateTo({ url: `/pages/article/detail/index?id=${article.id}` })}
|
||||
onPress={() => safeNavigateTo(`/pages/article/detail/index?id=${article.id}`)}
|
||||
activeFeedback="opacity"
|
||||
padding="none"
|
||||
>
|
||||
{article.cover_image && (
|
||||
<Image className='guest-article-cover' src={article.cover_image} mode='aspectFill' />
|
||||
<Image className='guest-article-cover' src={article.cover_image} mode='aspectFill' lazyLoad />
|
||||
)}
|
||||
<View className='guest-article-body'>
|
||||
<Text className='guest-article-title'>{article.title}</Text>
|
||||
@@ -229,7 +230,7 @@ function HomeDashboard({ modeClass }: { modeClass: string }) {
|
||||
return (
|
||||
<ContentCard
|
||||
key={item.label}
|
||||
onPress={() => Taro.navigateTo({ url: `/pages/pkg-health/trend/index?indicator=${item.indicator}` })}
|
||||
onPress={() => safeNavigateTo(`/pages/pkg-health/trend/index?indicator=${item.indicator}`)}
|
||||
activeFeedback="opacity"
|
||||
>
|
||||
<Text className='vital-label'>{item.label}</Text>
|
||||
@@ -259,8 +260,8 @@ function HomeDashboard({ modeClass }: { modeClass: string }) {
|
||||
key={r.id}
|
||||
className={`reminder-item ${i > 0 ? 'reminder-item-border' : ''}`}
|
||||
onClick={() => {
|
||||
if (r.type === 'appointment') Taro.navigateTo({ url: '/pages/appointment/index' });
|
||||
else if (r.type === 'followup') Taro.navigateTo({ url: `/pages/pkg-profile/followups/detail/index?id=${r.id}` });
|
||||
if (r.type === 'appointment') safeNavigateTo('/pages/appointment/index');
|
||||
else if (r.type === 'followup') safeNavigateTo(`/pages/pkg-profile/followups/detail/index?id=${r.id}`);
|
||||
}}
|
||||
>
|
||||
<Text className='reminder-tag'>{r.tag}</Text>
|
||||
@@ -275,7 +276,7 @@ function HomeDashboard({ modeClass }: { modeClass: string }) {
|
||||
<View className='action-btn action-primary' onClick={() => Taro.switchTab({ url: '/pages/health/index' })}>
|
||||
<Text className='action-btn-text'>记录体征</Text>
|
||||
</View>
|
||||
<View className='action-btn action-outline' onClick={() => Taro.navigateTo({ url: '/pages/appointment/create/index' })}>
|
||||
<View className='action-btn action-outline' onClick={() => safeNavigateTo('/pages/appointment/create/index')}>
|
||||
<Text className='action-btn-text'>预约挂号</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState } from 'react';
|
||||
import { View, Text, Input, Button } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { useAuthStore } from '../../stores/auth';
|
||||
import './index.scss';
|
||||
|
||||
@@ -191,9 +192,9 @@ export default function Login() {
|
||||
</View>
|
||||
<Text className="agreement-text">
|
||||
登录即同意
|
||||
<Text className="agreement-link" onClick={() => Taro.navigateTo({ url: '/pages/legal/user-agreement' })}>《用户协议》</Text>
|
||||
<Text className="agreement-link" onClick={() => safeNavigateTo('/pages/legal/user-agreement')}>《用户协议》</Text>
|
||||
和
|
||||
<Text className="agreement-link" onClick={() => Taro.navigateTo({ url: '/pages/legal/privacy-policy' })}>《隐私政策》</Text>
|
||||
<Text className="agreement-link" onClick={() => safeNavigateTo('/pages/legal/privacy-policy')}>《隐私政策》</Text>
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro, { useReachBottom } from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { listProducts } from '../../services/points';
|
||||
import type { PointsProduct } from '../../services/points';
|
||||
@@ -132,7 +133,7 @@ export default function Mall() {
|
||||
Taro.showToast({ title: '已兑完', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
Taro.navigateTo({ url: `/pages/pkg-mall/exchange/index?product_id=${item.id}` });
|
||||
safeNavigateTo(`/pages/pkg-mall/exchange/index?product_id=${item.id}`);
|
||||
};
|
||||
|
||||
const balance = account?.balance ?? 0;
|
||||
@@ -145,7 +146,7 @@ export default function Mall() {
|
||||
text='请先完善个人档案'
|
||||
hint='建档后即可使用积分商城、签到等功能'
|
||||
actionText='去建档'
|
||||
onAction={() => Taro.navigateTo({ url: '/pages/pkg-profile/family-add/index' })}
|
||||
onAction={() => safeNavigateTo('/pages/pkg-profile/family-add/index')}
|
||||
/>
|
||||
</PageShell>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro, { useRouter } from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import {
|
||||
getDialysisRecord, reviewDialysisRecord,
|
||||
@@ -167,9 +168,7 @@ export default function DialysisDetail() {
|
||||
</View>
|
||||
)}
|
||||
{record.status === 'draft' && (
|
||||
<View className='action-btn action-btn--secondary' onClick={() => Taro.navigateTo({
|
||||
url: `/pages/pkg-doctor-clinical/dialysis/create/index?id=${id}&version=${record.version}`,
|
||||
})}>
|
||||
<View className='action-btn action-btn--secondary' onClick={() => safeNavigateTo(`/pages/pkg-doctor-clinical/dialysis/create/index?id=${id}&version=${record.version}`)}>
|
||||
<Text className='action-btn__text'>编辑</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro, { useRouter } from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { listLabReports, type LabReportItem } from '@/services/doctor/labReport';
|
||||
import { listPatients } from '@/services/doctor/patient';
|
||||
@@ -99,9 +100,7 @@ export default function ReportList() {
|
||||
{reports.map((r) => (
|
||||
<ContentCard
|
||||
key={r.id}
|
||||
onPress={() => Taro.navigateTo({
|
||||
url: `/pages/pkg-doctor-clinical/report/detail/index?patientId=${currentPatientId}&id=${r.id}`,
|
||||
})}
|
||||
onPress={() => safeNavigateTo(`/pages/pkg-doctor-clinical/report/detail/index?patientId=${currentPatientId}&id=${r.id}`)}
|
||||
>
|
||||
<View className="report-card__header">
|
||||
<Text className="report-card__type">{r.report_type}</Text>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro, { useRouter } from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { listFollowUpTasks, type FollowUpTask } from '@/services/doctor/followup';
|
||||
import PageShell from '@/components/ui/PageShell';
|
||||
@@ -106,7 +107,7 @@ export default function FollowUpList() {
|
||||
{tasks.map((task) => (
|
||||
<ContentCard
|
||||
key={task.id}
|
||||
onPress={() => Taro.navigateTo({ url: `/pages/pkg-doctor-core/followup/detail/index?id=${task.id}` })}
|
||||
onPress={() => safeNavigateTo(`/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>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useMemo, useCallback } from 'react';
|
||||
import { View, Text, Input } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useDoctorClass } from '@/hooks/useDoctorClass';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
@@ -93,7 +94,7 @@ export default function DoctorHome() {
|
||||
usePageData(loadDashboard, { throttleMs: 10000 });
|
||||
|
||||
const handleCardClick = (card: CardConfig) => {
|
||||
Taro.navigateTo({ url: card.route });
|
||||
safeNavigateTo(card.route);
|
||||
};
|
||||
|
||||
const handleLogout = () => {
|
||||
@@ -123,7 +124,7 @@ export default function DoctorHome() {
|
||||
<View className='doctor-home__alert'>
|
||||
<Text className='doctor-home__alert-icon'>!</Text>
|
||||
<Text className='doctor-home__alert-text'>{alertCount} 位患者体征异常</Text>
|
||||
<Text className='doctor-home__alert-link' onClick={() => Taro.navigateTo({ url: '/pages/pkg-doctor-clinical/alerts/index' })}>查看 →</Text>
|
||||
<Text className='doctor-home__alert-link' onClick={() => safeNavigateTo('/pages/pkg-doctor-clinical/alerts/index')}>查看 →</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
@@ -131,7 +132,7 @@ export default function DoctorHome() {
|
||||
<Input
|
||||
className='doctor-home__search-input'
|
||||
placeholder='搜索患者姓名...'
|
||||
onFocus={() => Taro.navigateTo({ url: '/pages/pkg-doctor-core/patients/index' })}
|
||||
onFocus={() => safeNavigateTo('/pages/pkg-doctor-core/patients/index')}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -176,7 +177,7 @@ export default function DoctorHome() {
|
||||
<View
|
||||
key={action.route}
|
||||
className='quick-action'
|
||||
onClick={() => Taro.navigateTo({ url: action.route })}
|
||||
onClick={() => safeNavigateTo(action.route)}
|
||||
>
|
||||
<View className='quick-action__icon-wrap'>
|
||||
<Text className='quick-action__initial'>{action.initial}</Text>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro, { useRouter } from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { getPatient, getHealthSummary, type PatientDetail, type HealthSummary } from '@/services/doctor/patient';
|
||||
import Loading from '@/components/Loading';
|
||||
@@ -127,7 +128,7 @@ export default function PatientDetail() {
|
||||
<Text className='section-title'>近期化验</Text>
|
||||
<View
|
||||
className='lab-item'
|
||||
onClick={() => Taro.navigateTo({ url: `/pages/pkg-doctor-clinical/report/detail/index?patientId=${patientId}&id=${summary.latest_lab_report!.id}` })}
|
||||
onClick={() => safeNavigateTo(`/pages/pkg-doctor-clinical/report/detail/index?patientId=${patientId}&id=${summary.latest_lab_report!.id}`)}
|
||||
>
|
||||
<View className='lab-item__header'>
|
||||
<Text className='lab-item__type'>{summary.latest_lab_report.report_type}</Text>
|
||||
@@ -144,10 +145,10 @@ export default function PatientDetail() {
|
||||
<ContentCard>
|
||||
<Text className='section-title'>操作</Text>
|
||||
<View className='action-buttons'>
|
||||
<View className='action-btn' onClick={() => Taro.navigateTo({ url: `/pages/pkg-doctor-clinical/report/index?patientId=${patientId}` })}>
|
||||
<View className='action-btn' onClick={() => safeNavigateTo(`/pages/pkg-doctor-clinical/report/index?patientId=${patientId}`)}>
|
||||
<Text>查看化验报告</Text>
|
||||
</View>
|
||||
<View className='action-btn' onClick={() => Taro.navigateTo({ url: `/pages/pkg-doctor-core/followup/index?patientId=${patientId}` })}>
|
||||
<View className='action-btn' onClick={() => safeNavigateTo(`/pages/pkg-doctor-core/followup/index?patientId=${patientId}`)}>
|
||||
<Text>随访记录</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro, { useReachBottom } from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { listPatients, listPatientTags, type PatientItem, type PatientTag } from '@/services/doctor/patient';
|
||||
import PageShell from '@/components/ui/PageShell';
|
||||
@@ -118,7 +119,7 @@ export default function PatientList() {
|
||||
{patients.map((p) => (
|
||||
<ContentCard
|
||||
key={p.id}
|
||||
onPress={() => Taro.navigateTo({ url: `/pages/pkg-doctor-core/patients/detail/index?id=${p.id}` })}
|
||||
onPress={() => safeNavigateTo(`/pages/pkg-doctor-core/patients/detail/index?id=${p.id}`)}
|
||||
>
|
||||
<View className="patient-card__header">
|
||||
<Text className="patient-card__name">{p.name}</Text>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { listPatientAlerts, type Alert } from '@/services/alert';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
@@ -82,7 +83,7 @@ export default function PatientAlerts() {
|
||||
if (!currentPatient) {
|
||||
return (
|
||||
<PageShell padding="none" className={modeClass}>
|
||||
<ErrorState text='请先完善个人档案' onRetry={() => Taro.navigateTo({ url: '/pages/pkg-profile/family-add/index' })} />
|
||||
<ErrorState text='请先完善个人档案' onRetry={() => safeNavigateTo('/pages/pkg-profile/family-add/index')} />
|
||||
</PageShell>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { View, Text, Input, Picker } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { num, validateStr } from '@/utils/validate';
|
||||
import { inputVitalSign, getHealthThresholds, findThreshold, DEFAULT_THRESHOLDS, type HealthThreshold } from '../../../services/health';
|
||||
@@ -193,7 +194,7 @@ export default function HealthInput() {
|
||||
</View>
|
||||
|
||||
{/* 从设备同步入口 */}
|
||||
<View className='input-sync-entry' onClick={() => Taro.navigateTo({ url: '/pages/pkg-health/device-sync/index?returnTo=input' })}>
|
||||
<View className='input-sync-entry' onClick={() => safeNavigateTo('/pages/pkg-health/device-sync/index?returnTo=input')}>
|
||||
<Text className='input-sync-entry-text'>从设备同步</Text>
|
||||
<Text className='input-sync-entry-hint'>蓝牙连接设备自动获取数据</Text>
|
||||
</View>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro, { useReachBottom } from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { getCachedPatientId } from '@/services/request';
|
||||
import { listDialysisPrescriptions } from '@/services/dialysis';
|
||||
@@ -68,7 +69,7 @@ export default function DialysisPrescriptionList() {
|
||||
<View
|
||||
className='prescription-card'
|
||||
key={p.id}
|
||||
onClick={() => Taro.navigateTo({ url: `/pages/pkg-profile/dialysis-prescriptions/detail/index?id=${p.id}` })}
|
||||
onClick={() => safeNavigateTo(`/pages/pkg-profile/dialysis-prescriptions/detail/index?id=${p.id}`)}
|
||||
>
|
||||
<View className='prescription-card-top'>
|
||||
<Text className='prescription-model'>{p.dialyzer_model || '未指定型号'}</Text>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro, { useReachBottom } from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { getCachedPatientId } from '@/services/request';
|
||||
import { listDialysisRecords } from '@/services/dialysis';
|
||||
@@ -76,7 +77,7 @@ export default function DialysisRecordList() {
|
||||
<View
|
||||
className='record-card'
|
||||
key={r.id}
|
||||
onClick={() => Taro.navigateTo({ url: `/pages/pkg-profile/dialysis-records/detail/index?id=${r.id}` })}
|
||||
onClick={() => safeNavigateTo(`/pages/pkg-profile/dialysis-records/detail/index?id=${r.id}`)}
|
||||
>
|
||||
<View className='record-card-top'>
|
||||
<Text className={`type-tag ${ti.cls}`}>{ti.label}</Text>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { listPatients, Patient } from '../../../services/patient';
|
||||
import { useAuthStore } from '../../../stores/auth';
|
||||
@@ -42,12 +43,12 @@ export default function FamilyList() {
|
||||
};
|
||||
|
||||
const goToAdd = () => {
|
||||
Taro.navigateTo({ url: '/pages/pkg-profile/family-add/index' });
|
||||
safeNavigateTo('/pages/pkg-profile/family-add/index');
|
||||
};
|
||||
|
||||
const goToEdit = (patient: Patient) => {
|
||||
Taro.setStorageSync('edit_patient', patient);
|
||||
Taro.navigateTo({ url: `/pages/pkg-profile/family-add/index?id=${patient.id}` });
|
||||
safeNavigateTo(`/pages/pkg-profile/family-add/index?id=${patient.id}`);
|
||||
};
|
||||
|
||||
const genderText = (g?: string) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { listTasks, FollowUpTask } from '../../../services/followup';
|
||||
import EmptyState from '../../../components/EmptyState';
|
||||
@@ -45,7 +46,7 @@ export default function MyFollowUps() {
|
||||
};
|
||||
|
||||
const goToDetail = (id: string) => {
|
||||
Taro.navigateTo({ url: `/pages/pkg-profile/followups/detail/index?id=${id}` });
|
||||
safeNavigateTo(`/pages/pkg-profile/followups/detail/index?id=${id}`);
|
||||
};
|
||||
|
||||
const getStatusClass = (status: string) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro, { useReachBottom } from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { usePageData } from '@/hooks/usePageData';
|
||||
import { getCachedPatientId } from '@/services/request';
|
||||
import { listReports, LabReport } from '../../../services/report';
|
||||
@@ -49,7 +50,7 @@ export default function MyReports() {
|
||||
});
|
||||
|
||||
const goToDetail = (id: string) => {
|
||||
Taro.navigateTo({ url: `/pages/pkg-profile/reports/detail/index?id=${id}` });
|
||||
safeNavigateTo(`/pages/pkg-profile/reports/detail/index?id=${id}`);
|
||||
};
|
||||
|
||||
const formatStatus = (report: LabReport) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { useAuthStore } from '../../../stores/auth';
|
||||
import { invalidateHeadersCache, clearRequestCache } from '@/services/request';
|
||||
import { useElderClass } from '../../../hooks/useElderClass';
|
||||
@@ -51,7 +52,7 @@ export default function Settings() {
|
||||
};
|
||||
|
||||
const handlePrivacy = () => {
|
||||
Taro.navigateTo({ url: '/pages/legal/privacy-policy' });
|
||||
safeNavigateTo('/pages/legal/privacy-policy');
|
||||
};
|
||||
|
||||
const handleLogout = () => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { safeNavigateTo } from '@/utils/navigate';
|
||||
import { useState, useCallback } from 'react';
|
||||
import { useAuthStore } from '../../stores/auth';
|
||||
import { usePointsStore } from '../../stores/points';
|
||||
@@ -113,7 +114,7 @@ export default function Profile() {
|
||||
if (item.isSwitchTab) {
|
||||
Taro.switchTab({ url: item.path });
|
||||
} else {
|
||||
Taro.navigateTo({ url: item.path });
|
||||
safeNavigateTo(item.path);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -188,7 +189,7 @@ export default function Profile() {
|
||||
<ContentCard
|
||||
padding="none"
|
||||
margin="none"
|
||||
onPress={() => Taro.navigateTo({ url: '/pages/pkg-profile/notifications/index' })}
|
||||
onPress={() => safeNavigateTo('/pages/pkg-profile/notifications/index')}
|
||||
>
|
||||
<View className='menu-item'>
|
||||
<View className='menu-icon menu-icon--pri-l'>
|
||||
|
||||
@@ -81,12 +81,12 @@ export const useAuthStore = create<AuthState>((set, get) => ({
|
||||
restore: () => {
|
||||
// 利用内存缓存避免重复 Storage IPC + JSON.parse
|
||||
try {
|
||||
const userData = secureGet('user_data') || Taro.getStorageSync('user_data') || '';
|
||||
const userData = secureGet('user_data');
|
||||
if (userData !== cachedUserJson) {
|
||||
cachedUserJson = userData;
|
||||
cachedUserObj = userData ? JSON.parse(userData) : null;
|
||||
}
|
||||
const rolesData = secureGet('user_roles') || Taro.getStorageSync('user_roles') || '';
|
||||
const rolesData = secureGet('user_roles');
|
||||
if (rolesData !== cachedRolesJson) {
|
||||
cachedRolesJson = rolesData;
|
||||
cachedRolesObj = rolesData ? JSON.parse(rolesData) : [];
|
||||
@@ -252,6 +252,14 @@ export const useAuthStore = create<AuthState>((set, get) => ({
|
||||
Taro.removeStorageSync('current_patient_id');
|
||||
Taro.removeStorageSync('analytics_queue');
|
||||
Taro.removeStorageSync('edit_patient');
|
||||
Taro.removeStorageSync('ai_chat_history');
|
||||
// 清理 BLE DataBuffer 缓存(key 格式:ble_buffer_{patientId}_{bucket})
|
||||
const storageInfo = Taro.getStorageInfoSync();
|
||||
storageInfo.keys.forEach((key) => {
|
||||
if (key.startsWith('ble_buffer_') || key.startsWith('last_ble_sync')) {
|
||||
Taro.removeStorageSync(key);
|
||||
}
|
||||
});
|
||||
resetAllStores();
|
||||
set({ user: null, roles: [], currentPatient: null, patients: [] });
|
||||
Taro.reLaunch({ url: '/pages/index/index' });
|
||||
|
||||
Reference in New Issue
Block a user