From 1e59007bd5a5c5e907ea3a53c305bb0ed568f34f Mon Sep 17 00:00:00 2001 From: iven Date: Sun, 24 May 2026 11:32:40 +0800 Subject: [PATCH] =?UTF-8?q?fix(mp):=20DevTools=20=E5=8D=A1=E6=AD=BB=20+=20?= =?UTF-8?q?=E4=B8=BB=E5=8C=85=202MB=E2=86=92766KB=20+=20=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E8=B4=A8=E9=87=8F=204=20=E9=A1=B9=E5=85=A8=E9=80=9A=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:主包 2MB 全量组件注入导致 DevTools 渲染引擎内存渐增, 叠加离线时固定 3s 抑制期后的请求洪泛。 修复: - app.config.ts 添加 lazyCodeLoading: requiredComponents 主包 2.0MB→766KB,taro.js 526→131KB,vendors.js 230→28KB - request.ts 离线抑制改为指数退避(3s→6s→12s→30s cap) 后端不可达时自动延长抑制,防止请求风暴 - SegmentTabs Tab 接口改为 readonly,修复 TS 编译错误 - AbortController polyfill 补齐小程序运行时缺失 - 健康首页/设备同步/健康档案/报告/设置页 UI 重构 - 文章页公开端点适配游客访问 - 健康首页 Swiper 间隔优化 4s→5s,动画 500→300ms --- apps/miniprogram/.env.production | 4 +- apps/miniprogram/config/index.ts | 7 + apps/miniprogram/src/app.config.ts | 1 + apps/miniprogram/src/app.tsx | 1 + .../src/components/SegmentTabs/index.tsx | 6 +- apps/miniprogram/src/hooks/useAlertPolling.ts | 10 +- apps/miniprogram/src/pages/article/index.tsx | 24 +- apps/miniprogram/src/pages/health/index.scss | 171 +++- apps/miniprogram/src/pages/health/index.tsx | 40 +- apps/miniprogram/src/pages/index/index.tsx | 4 +- .../pages/pkg-health/device-sync/index.scss | 965 +++++++++++++++--- .../pages/pkg-health/device-sync/index.tsx | 507 ++++++--- .../pkg-profile/health-records/index.scss | 86 +- .../pkg-profile/health-records/index.tsx | 204 +++- .../src/pages/pkg-profile/reports/index.scss | 63 +- .../src/pages/pkg-profile/reports/index.tsx | 195 +++- .../src/pages/pkg-profile/settings/index.scss | 11 + .../src/pages/pkg-profile/settings/index.tsx | 13 + apps/miniprogram/src/services/analytics.ts | 22 +- apps/miniprogram/src/services/article.ts | 46 +- .../src/services/ble/BLEManager.ts | 52 +- .../ble/adapters/GenericBleAdapter.ts | 26 + .../src/services/ble/adapters/index.ts | 2 +- apps/miniprogram/src/services/request.ts | 46 +- apps/miniprogram/src/stores/auth.ts | 10 +- .../src/utils/abort-controller-polyfill.ts | 57 ++ apps/web/src/api/health/articles.ts | 3 + .../health/articleEditor/ArticleEditor.tsx | 12 +- .../articleEditor/ArticleSettingsDrawer.tsx | 17 +- crates/erp-health/src/dto/article_dto.rs | 13 + crates/erp-health/src/entity/article.rs | 2 + .../src/handler/article_category_handler.rs | 28 +- .../erp-health/src/handler/article_handler.rs | 2 + crates/erp-health/src/module.rs | 8 +- .../erp-health/src/service/article_service.rs | 12 +- crates/erp-server/_server_err3.txt | 3 + crates/erp-server/migration/src/lib.rs | 2 + ...260521_000158_alerts_add_source_columns.rs | 37 + ...1_000159_patient_phone_and_consent_seed.rs | 108 ++ .../m20260522_000160_article_add_is_public.rs | 34 + ...62_seed_patient_miniprogram_permissions.rs | 170 +++ .../tests/integration/health_article_tests.rs | 7 + dev.ps1 | 4 +- docs/audits/v3-beta/01-executive-summary.md | 97 ++ docs/audits/v3-beta/02-web-functional.md | 119 +++ docs/audits/v3-beta/03-web-perf-compat.md | 175 ++++ docs/audits/v3-beta/04-miniprogram.md | 146 +++ docs/audits/v3-beta/05-api-deep-test.md | 159 +++ docs/audits/v3-beta/06-static-analysis.md | 139 +++ docs/audits/v3-beta/07-brainstorm.md | 222 ++++ docs/audits/v3-beta/08-beta-checklist.md | 142 +++ .../mp-device-sync-redesign-preview.png | Bin 0 -> 278870 bytes docs/design/mp-device-sync-redesign.html | 754 ++++++++++++++ docs/design/mp-device-sync-redesign/META.yml | 12 + docs/design/mp-device-sync-redesign/SPEC.md | 246 +++++ ...miniprogram-production-ready-brainstorm.md | 104 ++ .../2026-05-22-my-page-subpages-necessity.md | 92 ++ docs/健康管理/HMS系统设计思路.md | 2 +- 58 files changed, 4950 insertions(+), 494 deletions(-) create mode 100644 apps/miniprogram/src/utils/abort-controller-polyfill.ts create mode 100644 crates/erp-server/_server_err3.txt create mode 100644 crates/erp-server/migration/src/m20260521_000158_alerts_add_source_columns.rs create mode 100644 crates/erp-server/migration/src/m20260521_000159_patient_phone_and_consent_seed.rs create mode 100644 crates/erp-server/migration/src/m20260522_000160_article_add_is_public.rs create mode 100644 crates/erp-server/migration/src/m20260522_000162_seed_patient_miniprogram_permissions.rs create mode 100644 docs/audits/v3-beta/01-executive-summary.md create mode 100644 docs/audits/v3-beta/02-web-functional.md create mode 100644 docs/audits/v3-beta/03-web-perf-compat.md create mode 100644 docs/audits/v3-beta/04-miniprogram.md create mode 100644 docs/audits/v3-beta/05-api-deep-test.md create mode 100644 docs/audits/v3-beta/06-static-analysis.md create mode 100644 docs/audits/v3-beta/07-brainstorm.md create mode 100644 docs/audits/v3-beta/08-beta-checklist.md create mode 100644 docs/design/mp-device-sync-redesign-preview.png create mode 100644 docs/design/mp-device-sync-redesign.html create mode 100644 docs/design/mp-device-sync-redesign/META.yml create mode 100644 docs/design/mp-device-sync-redesign/SPEC.md create mode 100644 docs/discussions/2026-05-20-miniprogram-production-ready-brainstorm.md create mode 100644 docs/discussions/2026-05-22-my-page-subpages-necessity.md diff --git a/apps/miniprogram/.env.production b/apps/miniprogram/.env.production index 70d3710..ae59394 100644 --- a/apps/miniprogram/.env.production +++ b/apps/miniprogram/.env.production @@ -1,3 +1,5 @@ TARO_APP_API_URL=https://api.hms.example.com/api/v1 TARO_APP_DEFAULT_TENANT_ID= -TARO_APP_ENCRYPTION_KEY= +# TARO_APP_ENCRYPTION_KEY 不在此文件设置 +# 生产密钥通过 CI/CD 环境变量注入(dotenv 不覆盖已有 env var) +# 本地 build:weapp 测试时自动回退到 .env 中的开发密钥 diff --git a/apps/miniprogram/config/index.ts b/apps/miniprogram/config/index.ts index 3d89c95..9a2285c 100644 --- a/apps/miniprogram/config/index.ts +++ b/apps/miniprogram/config/index.ts @@ -2,6 +2,12 @@ import { defineConfig } from '@tarojs/cli'; import path from 'path'; export default defineConfig(async (merge) => { + // 生产构建缺少加密密钥时发出警告(不阻断构建,但提示开发者/CI 配置) + if (process.env.NODE_ENV === 'production' && !process.env.TARO_APP_ENCRYPTION_KEY) { + console.warn('[config] ⚠ TARO_APP_ENCRYPTION_KEY 未设置,将回退到 .env 中的开发密钥'); + console.warn('[config] 生产部署应通过 CI/CD 环境变量注入独立密钥'); + } + const baseConfig = { projectName: 'hms-miniprogram', date: '2026-4-23', @@ -19,6 +25,7 @@ export default defineConfig(async (merge) => { 'process.env.TARO_APP_WX_TEMPLATE_REPORT': JSON.stringify(process.env.TARO_APP_WX_TEMPLATE_REPORT || ''), 'process.env.TARO_APP_WX_TEMPLATE_CRITICAL_ALERT': JSON.stringify(process.env.TARO_APP_WX_TEMPLATE_CRITICAL_ALERT || ''), 'process.env.TARO_APP_WX_TEMPLATE_HEALTH_ABNORMAL': JSON.stringify(process.env.TARO_APP_WX_TEMPLATE_HEALTH_ABNORMAL || ''), + 'process.env.TARO_APP_WX_TEMPLATE_MEDICATION': JSON.stringify(process.env.TARO_APP_WX_TEMPLATE_MEDICATION || ''), 'process.env.TARO_APP_DEFAULT_TENANT_ID': JSON.stringify(process.env.TARO_APP_DEFAULT_TENANT_ID || ''), 'process.env.TARO_APP_DEV_USER': JSON.stringify( process.env.NODE_ENV === 'production' ? '' : (process.env.TARO_APP_DEV_USER || '') diff --git a/apps/miniprogram/src/app.config.ts b/apps/miniprogram/src/app.config.ts index 68c465e..cc16c3b 100644 --- a/apps/miniprogram/src/app.config.ts +++ b/apps/miniprogram/src/app.config.ts @@ -1,4 +1,5 @@ export default defineAppConfig({ + lazyCodeLoading: 'requiredComponents', pages: [ 'pages/index/index', 'pages/login/index', diff --git a/apps/miniprogram/src/app.tsx b/apps/miniprogram/src/app.tsx index 7565dee..3b42d50 100644 --- a/apps/miniprogram/src/app.tsx +++ b/apps/miniprogram/src/app.tsx @@ -1,4 +1,5 @@ import './utils/crypto-polyfill'; +import './utils/abort-controller-polyfill'; import { useEffect, useRef, PropsWithChildren } from 'react'; import { useDidShow, useDidHide } from '@tarojs/taro'; import ErrorBoundary from './components/ErrorBoundary'; diff --git a/apps/miniprogram/src/components/SegmentTabs/index.tsx b/apps/miniprogram/src/components/SegmentTabs/index.tsx index b281294..7072dac 100644 --- a/apps/miniprogram/src/components/SegmentTabs/index.tsx +++ b/apps/miniprogram/src/components/SegmentTabs/index.tsx @@ -3,12 +3,12 @@ import { View, Text } from '@tarojs/components'; import './index.scss'; interface Tab { - key: string; - label: string; + readonly key: string; + readonly label: string; } interface SegmentTabsProps { - tabs: Tab[]; + tabs: readonly Tab[]; activeKey: string; onChange: (key: string) => void; variant?: 'underline' | 'pill'; diff --git a/apps/miniprogram/src/hooks/useAlertPolling.ts b/apps/miniprogram/src/hooks/useAlertPolling.ts index 34f7e10..ea8f864 100644 --- a/apps/miniprogram/src/hooks/useAlertPolling.ts +++ b/apps/miniprogram/src/hooks/useAlertPolling.ts @@ -79,8 +79,14 @@ export function useAlertPolling() { s.lastAlertCount = count; failCount = 0; - } catch { - failCount++; + } catch (err) { + // 权限不足时立即停止轮询,不再重试(避免反复弹 toast) + if (err instanceof Error && err.message === '权限不足') { + s.failCount = MAX_FAILURES; + return; + } + // 网络异常时快速累积失败计数(离线抑制下会在 3s 内快速耗尽重试) + failCount += 3; } if (gen !== s.generation) return; diff --git a/apps/miniprogram/src/pages/article/index.tsx b/apps/miniprogram/src/pages/article/index.tsx index 449db3d..13268d5 100644 --- a/apps/miniprogram/src/pages/article/index.tsx +++ b/apps/miniprogram/src/pages/article/index.tsx @@ -3,7 +3,13 @@ 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 } from '../../services/article'; +import { useAuthStore } from '@/stores/auth'; +import { + listArticles, + listCategories, + listPublicArticles, + listPublicCategories, +} from '../../services/article'; import PageShell from '@/components/ui/PageShell'; import ContentCard from '@/components/ui/ContentCard'; import LoadingCard from '@/components/ui/LoadingCard'; @@ -33,6 +39,7 @@ interface ArticleCategory { export default function ArticleList() { const modeClass = useElderClass(); + const isLoggedIn = !!useAuthStore((s) => s.user); const [articles, setArticles] = useState([]); const [, setPage] = useState(1); const [, setTotal] = useState(0); @@ -46,10 +53,9 @@ export default function ArticleList() { setError(false); try { const cid = categoryId !== undefined ? categoryId : activeCategory; - const res = await listArticles({ - page: p, - category_id: cid || undefined, - }); + const res = isLoggedIn + ? await listArticles({ page: p, category_id: cid || undefined }) + : await listPublicArticles({ page: p, category_id: cid || undefined }); const list = res.data || []; setArticles(append ? (prev) => [...prev, ...list] : list); setTotal(res.total); @@ -61,19 +67,21 @@ export default function ArticleList() { } finally { setLoading(false); } - }, [activeCategory]); + }, [activeCategory, isLoggedIn]); usePageData( useCallback(async () => { try { - const cats = await listCategories(); + const cats = isLoggedIn + ? await listCategories() + : await listPublicCategories(); setCategories(cats || []); } catch (err) { console.warn('[article] 加载分类失败:', err); setCategories([]); } await fetchData(1); - }, [fetchData]), + }, [fetchData, isLoggedIn]), { throttleMs: 10000, enablePullDown: true }, ); diff --git a/apps/miniprogram/src/pages/health/index.scss b/apps/miniprogram/src/pages/health/index.scss index 01b4ef4..abefae1 100644 --- a/apps/miniprogram/src/pages/health/index.scss +++ b/apps/miniprogram/src/pages/health/index.scss @@ -7,7 +7,10 @@ /* ─── 页头 ─── */ .health-header { - margin-bottom: var(--tk-section-gap); + margin-bottom: var(--tk-gap-sm); + display: flex; + align-items: baseline; + justify-content: space-between; } .health-title { @@ -15,11 +18,50 @@ font-size: var(--tk-font-h1); font-weight: 700; color: $tx; + letter-spacing: -0.02em; } -/* ─── 今日体征摘要 ─── */ +.health-date { + font-size: var(--tk-font-cap); + color: $tx3; +} + +/* ─── 今日体征 hero 卡片 ─── */ .vitals-grid { margin-bottom: var(--tk-section-gap); + background: linear-gradient(135deg, $card 60%, $pri-l); + border-radius: var(--tk-card-radius); + box-shadow: $shadow-md; + padding: var(--tk-card-padding); + + /* 覆盖 ContentCard 默认 padding/margin */ + &.content-card { + padding: var(--tk-card-padding); + margin-bottom: var(--tk-section-gap); + } +} + +.vitals-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: var(--tk-gap-md); +} + +.vitals-title { + font-size: var(--tk-font-body-sm); + font-weight: 600; + color: $tx2; + letter-spacing: 0.04em; +} + +.vitals-badge { + font-size: var(--tk-font-micro); + color: $acc; + background: $acc-l; + padding: 3px 10px; + border-radius: $r-pill; + font-weight: 500; } .vitals-row { @@ -30,9 +72,13 @@ .vital-cell { text-align: center; - padding: var(--tk-gap-sm); + padding: var(--tk-gap-md) var(--tk-gap-sm); border-radius: $r-sm; background: $bg; + + &:active { + opacity: var(--tk-touch-feedback-opacity); + } } .vital-value { @@ -40,7 +86,9 @@ font-size: var(--tk-font-num); font-weight: 700; color: $tx; + font-variant-numeric: tabular-nums; display: block; + line-height: 1.1; } .vital-unit { @@ -53,8 +101,9 @@ .vital-label { font-size: var(--tk-font-cap); color: $tx2; + font-weight: 500; display: block; - margin-top: 4px; + margin-top: 6px; } .vital-cell.vital-warn { @@ -71,11 +120,11 @@ } } -/* ─── 快捷入口 ─── */ +/* ─── 快捷入口 — 横排 4 格图标 ─── */ .quick-entries { display: grid; grid-template-columns: repeat(4, 1fr); - gap: var(--tk-gap-sm); + gap: var(--tk-gap-xs); margin-bottom: var(--tk-section-gap); } @@ -86,6 +135,7 @@ gap: var(--tk-gap-xs); min-height: var(--tk-touch-min); justify-content: center; + padding: var(--tk-gap-sm) 0; &:active { opacity: var(--tk-touch-feedback-opacity); @@ -93,17 +143,47 @@ } .quick-icon { - width: 48px; - height: 48px; - border-radius: $r; - background: var(--tk-pri-l); + width: 44px; + height: 44px; + border-radius: $r-sm; @include flex-center; } .quick-icon-text { - font-size: var(--tk-font-body); + font-size: 18px; font-weight: 600; - color: var(--tk-pri); +} + +.quick-icon--input { + background: $pri-l; + + .quick-icon-text { + color: $pri; + } +} + +.quick-icon--trend { + background: $doc-pri-l; + + .quick-icon-text { + color: $doc-pri; + } +} + +.quick-icon--report { + background: $acc-l; + + .quick-icon-text { + color: $acc; + } +} + +.quick-icon--med { + background: $wrn-l; + + .quick-icon-text { + color: $wrn; + } } .quick-label { @@ -112,12 +192,21 @@ font-weight: 500; } -/* ─── 告警提示 ─── */ +/* ─── 告警横幅 ─── */ .alert-hint { display: flex; align-items: center; gap: var(--tk-gap-sm); margin-bottom: var(--tk-section-gap); + background: $dan-l; + border-radius: $r-sm; + + /* 覆盖 ContentCard 默认样式 */ + &.content-card { + background: $dan-l; + box-shadow: none; + border: none; + } &:active { opacity: var(--tk-touch-feedback-opacity); @@ -125,8 +214,8 @@ } .alert-dot { - width: 10px; - height: 10px; + width: 8px; + height: 8px; border-radius: 50%; background: $dan; flex-shrink: 0; @@ -141,8 +230,9 @@ .alert-arrow { font-size: var(--tk-font-body); - color: $tx3; + color: $dan; flex-shrink: 0; + opacity: 0.6; } /* ─── 趋势图 ─── */ @@ -183,7 +273,7 @@ left: 8px; right: 8px; border-top: 1.5px dashed $wrn; - opacity: 0.6; + opacity: 0.5; pointer-events: none; } @@ -193,7 +283,7 @@ top: -16px; font-size: var(--tk-font-micro); color: $wrn; - opacity: 0.8; + opacity: 0.7; } .trend-bar-col { @@ -206,17 +296,18 @@ } .trend-bar { - width: 28px; + width: 24px; border-radius: $r-xs $r-xs 0 0; - min-height: 8px; - opacity: 0.8; + min-height: 6px; &.trend-bar-normal { background: var(--tk-pri); + opacity: 0.75; } &.trend-bar-warn { background: $wrn; + opacity: 0.85; } } @@ -286,30 +377,42 @@ } .article-entry-text { - font-size: var(--tk-font-cap); + font-size: var(--tk-font-body-sm); color: $tx; font-weight: 500; } /* ─── AI 建议卡片 ─── */ .ai-suggestion-card { - background: $acc-l; + background: linear-gradient(135deg, #F0F7F0 0%, $acc-l 100%); border-radius: $r; - padding: var(--tk-gap-md); + padding: var(--tk-card-padding); margin-bottom: var(--tk-section-gap); box-shadow: none; - border-left: 4px solid $acc; + position: relative; + overflow: hidden; + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 3px; + background: linear-gradient(90deg, $acc, $acc 60%, transparent); + border-radius: 3px 3px 0 0; + } } .ai-card-header { display: flex; justify-content: space-between; align-items: center; - margin-bottom: var(--tk-gap-xs); + margin-bottom: var(--tk-gap-md); } .ai-card-title { - font-size: var(--tk-font-cap); + font-size: var(--tk-font-body-sm); font-weight: 600; color: $acc; } @@ -321,8 +424,8 @@ } .ai-suggestion-item { - padding: var(--tk-gap-xs) 0; - border-bottom: 1px solid rgba($acc, 0.15); + padding: var(--tk-gap-sm) 0; + border-bottom: 1px solid rgba($acc, 0.12); &:last-child { border-bottom: none; @@ -331,7 +434,7 @@ .ai-suggestion-main { display: flex; - align-items: center; + align-items: flex-start; gap: var(--tk-gap-xs); &:active { @@ -344,6 +447,7 @@ height: 8px; border-radius: 50%; flex-shrink: 0; + margin-top: 5px; &.ai-risk-high { background: $dan; @@ -362,19 +466,20 @@ font-size: var(--tk-font-cap); color: $tx2; line-height: 1.6; + flex: 1; } /* ─── AI 建议反馈按钮 ─── */ .ai-feedback-row { display: flex; gap: var(--tk-gap-xs); - margin-top: var(--tk-gap-2xs); + margin-top: var(--tk-gap-xs); padding-left: 20px; } .ai-feedback-btn { - height: 44px; - min-height: 44px; + height: 36px; + min-height: 36px; border-radius: $r-xs; @include flex-center; padding: 0 var(--tk-gap-sm); diff --git a/apps/miniprogram/src/pages/health/index.tsx b/apps/miniprogram/src/pages/health/index.tsx index 14aed5b..4045a4c 100644 --- a/apps/miniprogram/src/pages/health/index.tsx +++ b/apps/miniprogram/src/pages/health/index.tsx @@ -13,10 +13,10 @@ import { submitSuggestionFeedback } from '../../services/ai-analysis'; import './index.scss'; const QUICK_ENTRIES = [ - { label: '录入体征', icon: '笔', path: '/pages/pkg-health/input/index' }, - { label: '健康趋势', icon: '线', path: '/pages/pkg-health/trend/index' }, - { label: '我的报告', icon: '报', path: '/pages/pkg-profile/reports/index' }, - { label: '用药记录', icon: '药', path: '/pages/pkg-profile/medication/index' }, + { label: '录入体征', icon: '✏', color: 'input', path: '/pages/pkg-health/input/index' }, + { label: '健康趋势', icon: '📈', color: 'trend', path: '/pages/pkg-health/trend/index' }, + { label: '我的报告', icon: '📋', color: 'report', path: '/pages/pkg-profile/reports/index' }, + { label: '健康档案', icon: '健', color: 'med', path: '/pages/pkg-profile/health-records/index' }, ] as const; function statusClass(status?: string): string { @@ -26,6 +26,14 @@ function statusClass(status?: string): string { return 'vital-ok'; } +function formatDate(): string { + const d = new Date(); + const month = d.getMonth() + 1; + const day = d.getDate(); + const weekDays = ['日', '一', '二', '三', '四', '五', '六']; + return `${month}月${day}日 周${weekDays[d.getDay()]}`; +} + export default function Health() { const user = useAuthStore((s) => s.user); const modeClass = useElderClass(); @@ -59,6 +67,7 @@ export default function Health() { { label: '血糖', value: summary.blood_sugar ? `${summary.blood_sugar.value}` : '—', unit: 'mmol/L', status: summary.blood_sugar?.status }, { label: '体重', value: summary.weight ? `${summary.weight.value}` : '—', unit: 'kg', status: summary.weight?.status }, ]; + const recordedCount = vitals.filter((v) => v.value !== '—').length; const getThresholdValue = (type: VitalType): number | null => { if (!thresholds.length) return null; @@ -82,10 +91,17 @@ export default function Health() { 健康总览 + {formatDate()} - {/* 今日体征摘要 */} - + {/* 今日体征 hero 卡片 */} + + + 今日体征 + {recordedCount > 0 && ( + 已记录 {recordedCount} 项 + )} + {loading ? : ( {vitals.map((v) => ( @@ -97,9 +113,9 @@ export default function Health() { ))} )} - + - {/* 快捷入口 */} + {/* 快捷入口 — 横排 4 格图标 */} {QUICK_ENTRIES.map((e) => ( safeNavigateTo(e.path)} > - + {e.icon} {e.label} @@ -115,10 +131,12 @@ export default function Health() { ))} - {/* 告警提示 */} + {/* 告警横幅 */} {alertCount > 0 && ( safeNavigateTo('/pages/pkg-health/alerts/index')} > diff --git a/apps/miniprogram/src/pages/index/index.tsx b/apps/miniprogram/src/pages/index/index.tsx index 663d252..aeea7f4 100644 --- a/apps/miniprogram/src/pages/index/index.tsx +++ b/apps/miniprogram/src/pages/index/index.tsx @@ -105,8 +105,8 @@ function GuestHome({ modeClass }: { modeClass: string }) { indicatorActiveColor='#FFFFFF' autoplay={swiperAutoplay} circular - interval={4000} - duration={500} + interval={5000} + duration={300} > {slides.map((slide, idx) => ( diff --git a/apps/miniprogram/src/pages/pkg-health/device-sync/index.scss b/apps/miniprogram/src/pages/pkg-health/device-sync/index.scss index d6f7669..e2e08ea 100644 --- a/apps/miniprogram/src/pages/pkg-health/device-sync/index.scss +++ b/apps/miniprogram/src/pages/pkg-health/device-sync/index.scss @@ -2,245 +2,928 @@ @import '../../../styles/mixins.scss'; // PageShell 已接管:min-height, background, safe-bottom -// ContentCard 已接管:sync-status-card/sync-result-card 背景/圆角/阴影 +// NavBar 由 Taro 原生页面配置处理(index.config.ts navigationBarTitleText) -.sync-header { - background: var(--tk-pri); - padding: var(--tk-gap-2xl) var(--tk-gap-xl) var(--tk-gap-xl); - color: $card; +// ─── Body ─── +.ds-body { + padding: 0 var(--tk-gap-lg) calc(var(--tk-tabbar-space) + 20px); + + &--center { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 60vh; + padding-top: 0; + } } -.sync-header-title { - @include section-title; - color: $card; -} - -.sync-section { - padding: var(--tk-gap-lg); -} - -.sync-hero { +// ─── Hero ─── +.ds-hero { + background: linear-gradient(135deg, $pri 0%, $pri-d 100%); + margin: 0 calc(var(--tk-gap-lg) * -1); + padding: var(--tk-gap-2xl) var(--tk-gap-lg) var(--tk-gap-xl); display: flex; flex-direction: column; align-items: center; - padding: var(--tk-gap-2xl) var(--tk-gap-lg); - background: $card; - border-radius: $r; margin-bottom: var(--tk-gap-lg); - box-shadow: $shadow-sm; } -.sync-hero-icon { - width: 80px; - height: 80px; +.ds-hero__icon { + width: 72px; + height: 72px; border-radius: 50%; - background: var(--tk-pri-l); + background: rgba(255, 255, 255, 0.15); @include flex-center; margin-bottom: var(--tk-section-gap); - color: var(--tk-pri); - font-family: 'Georgia', 'Times New Roman', serif; - font-size: var(--tk-font-num-lg); - font-weight: bold; } -.sync-hero-title { +.ds-hero__bt { + font-size: 24px; + font-weight: 700; + color: $white; + font-family: Georgia, 'Times New Roman', serif; +} + +.ds-hero__title { @include section-title; + color: $white; + font-family: Georgia, 'Times New Roman', serif; margin-bottom: var(--tk-gap-xs); } -.sync-hero-desc { - font-size: var(--tk-font-h1); +.ds-hero__desc { + font-size: var(--tk-font-body-sm); + color: rgba(255, 255, 255, 0.75); + text-align: center; +} + +// ─── 设备类型标签 ─── +.ds-types { + margin-bottom: var(--tk-gap-md); +} + +.ds-types__label { + display: block; + font-size: var(--tk-font-body-sm); + font-weight: 600; + color: $tx; + margin-bottom: var(--tk-gap-sm); + padding-left: 2px; +} + +.ds-types__row { + display: flex; + gap: var(--tk-gap-xs); +} + +.ds-type-tag { + display: flex; + align-items: center; + gap: 6px; + background: $card; + border: 1px solid $bd-l; + border-radius: $r-xs; + padding: 8px 12px; +} + +.ds-type-tag__dot { + width: 8px; + height: 8px; + border-radius: 50%; + + &--heart { background: $dan; } + &--bp { background: $pri; } + &--glu { background: $wrn; } +} + +.ds-type-tag__text { + font-size: var(--tk-font-cap); color: $tx2; } -.sync-action { - @include flex-center; - background: var(--tk-pri); - border-radius: $r-sm; - padding: var(--tk-section-gap) var(--tk-gap-2xl); - margin: var(--tk-gap-sm) 0; - - &--primary { - flex: 1; - background: var(--tk-pri); - } - - &--danger { - flex: 1; - background: $dan; - margin-left: var(--tk-gap-md); - } +// ─── 上次同步信息 ─── +.ds-sync-info { + margin-bottom: var(--tk-gap-sm) !important; } -.sync-action-text { - color: $card; - font-size: var(--tk-font-body-lg); - font-weight: 500; -} - -.sync-device-list { - margin-top: var(--tk-gap-md); -} - -.sync-section-title { - font-family: 'Georgia', 'Times New Roman', serif; - font-size: var(--tk-font-body-lg); - font-weight: bold; - color: $tx; - margin-bottom: var(--tk-gap-sm); - display: block; -} - -.sync-device-item { +.ds-sync-info__inner { display: flex; - justify-content: space-between; align-items: center; - background: $card; - border-radius: $r-sm; - padding: var(--tk-gap-lg); - margin-bottom: var(--tk-gap-sm); - box-shadow: $shadow-sm; + gap: var(--tk-gap-md); } -.sync-device-info { +.ds-sync-info__icon-wrap { + width: 36px; + height: 36px; + border-radius: 50%; + background: $acc-l; + @include flex-center; + flex-shrink: 0; +} + +.ds-sync-info__check { + font-size: 16px; + color: $acc; + font-weight: 700; +} + +.ds-sync-info__text { + flex: 1; display: flex; flex-direction: column; } -.sync-device-name { - font-size: var(--tk-font-body-lg); +.ds-sync-info__title { + font-size: var(--tk-font-body-sm); font-weight: 500; color: $tx; } -.sync-device-adapter { - font-size: var(--tk-font-body); - color: var(--tk-text-secondary); - margin-top: 4px; +.ds-sync-info__time { + font-size: var(--tk-font-cap); + color: $tx3; + margin-top: 2px; } -.sync-device-rssi { - font-size: var(--tk-font-body); - color: $tx2; +.ds-sync-info__badge { + background: $acc-l; + border-radius: $r-xs; + padding: 4px 10px; + font-size: var(--tk-font-cap); + color: $acc; + font-weight: 500; } -.sync-status-card { +// ─── 待上传警告 ─── +.ds-warning { + background: $wrn-l; + border-radius: $r-sm; + padding: 12px var(--tk-gap-md); display: flex; align-items: center; - margin-bottom: var(--tk-gap-md); + gap: 10px; + margin-bottom: var(--tk-gap-lg); } -.sync-status-dot { - width: 16px; - height: 16px; +.ds-warning__icon { + width: 20px; + height: 20px; border-radius: 50%; - margin-right: var(--tk-gap-md); - background: $tx3; + background: $wrn; + color: $white; + font-size: 12px; + font-weight: 700; + @include flex-center; + flex-shrink: 0; +} - &--connected { +.ds-warning__text { + font-size: var(--tk-font-cap); + color: $wrn; + font-weight: 500; +} + +// ─── 扫描按钮 ─── +.ds-scan-btn-wrap { + margin-top: var(--tk-gap-md); +} + +// ─── 设备列表 ─── +.ds-devices { + margin-top: var(--tk-gap-lg); +} + +.ds-devices__header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: var(--tk-gap-sm); +} + +.ds-devices__count { + font-size: var(--tk-font-body-sm); + font-weight: 600; + color: $tx; +} + +.ds-devices__rescan { + font-size: var(--tk-font-cap); + color: $pri; + font-weight: 500; +} + +.ds-device-card { + display: flex; + align-items: center; + gap: 14px; + background: $card; + border-radius: $r-sm; + padding: var(--tk-gap-md); + margin-bottom: 10px; + border: 1px solid $bd-l; +} + +.ds-device-card__icon { + width: 44px; + height: 44px; + border-radius: $r-sm; + background: $pri-l; + @include flex-center; + flex-shrink: 0; +} + +.ds-device-card__bt { + font-size: 14px; + font-weight: 700; + color: $pri; + font-family: Georgia, 'Times New Roman', serif; +} + +.ds-device-card__info { + flex: 1; + display: flex; + flex-direction: column; +} + +.ds-device-card__name { + font-size: var(--tk-font-body); + font-weight: 600; + color: $tx; +} + +.ds-device-card__adapter { + font-size: var(--tk-font-cap); + color: $tx3; + margin-top: 3px; +} + +.ds-device-card__signal { + display: flex; + align-items: flex-end; + gap: 2px; + height: 16px; + margin-right: 6px; +} + +.ds-signal-bar { + width: 3px; + border-radius: 1px; + background: $bd; + + &--active { background: $acc; } } -.sync-status-text { - font-size: var(--tk-font-body-lg); +.ds-device-card__arrow { + font-size: 18px; + color: $tx3; + font-weight: 300; +} + +.ds-device-card--generic { + border-style: dashed; + border-color: $bd; + + .ds-device-card__icon { + background: $surface-alt; + } +} + +.ds-devices__empty-hint { + margin-top: var(--tk-gap-md); + background: $card; + border-radius: $r-sm; + padding: 14px var(--tk-gap-md); + border: 1px dashed $bd; + display: flex; + align-items: center; + gap: 10px; +} + +.ds-devices__empty-icon { + width: 32px; + height: 32px; + border-radius: 50%; + background: $surface-alt; + @include flex-center; + font-size: 14px; + color: $tx3; + flex-shrink: 0; +} + +.ds-devices__empty-title { + display: block; + font-size: var(--tk-font-cap); + color: $tx2; +} + +.ds-devices__empty-desc { + display: block; + font-size: var(--tk-font-cap); + color: $tx3; + margin-top: 2px; +} + +// 空结果提示框(扫描完成但 0 设备) +.ds-devices--empty { + display: flex; + flex-direction: column; + gap: var(--tk-gap-md); +} + +.ds-devices__empty-box { + background: $card; + border-radius: $r; + border: 2px dashed $bd; + padding: var(--tk-gap-xl) var(--tk-gap-lg); + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + gap: var(--tk-gap-xs); +} + +.ds-devices__empty-box-icon { + width: 48px; + height: 48px; + border-radius: 50%; + background: $wrn-l; + color: $wrn; + font-size: 22px; + font-weight: 700; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: var(--tk-gap-xs); +} + +.ds-devices__empty-box-title { + font-size: var(--tk-font-body); + font-weight: 600; color: $tx; } -.sync-readings-panel { +.ds-devices__empty-box-desc { + font-size: var(--tk-font-body-sm); + color: $tx3; + line-height: 1.5; +} + +.ds-devices__rescan-wrap { + margin-top: var(--tk-gap-xs); +} + +// ─── 脉冲扫描动画 ─── +.ds-pulse { + position: relative; + width: 140px; + height: 140px; + margin-bottom: var(--tk-gap-2xl); +} + +.ds-pulse__ring { + position: absolute; + border-radius: 50%; + border: 2px solid $pri-l; + animation: ds-pulse-ring 2s ease-out infinite; + + &--1 { top: 0; left: 0; width: 140px; height: 140px; } + &--2 { top: 15px; left: 15px; width: 110px; height: 110px; animation-delay: 0.5s; } +} + +.ds-pulse__center { + position: absolute; + top: 30px; + left: 30px; + width: 80px; + height: 80px; + border-radius: 50%; + background: $pri-l; + @include flex-center; + animation: ds-pulse-dot 2s ease-in-out infinite; +} + +.ds-pulse__bt { + font-size: 24px; + font-weight: 700; + color: $pri; + font-family: Georgia, 'Times New Roman', serif; +} + +.ds-pulse__title { + font-family: Georgia, 'Times New Roman', serif; + font-size: var(--tk-font-h2); + font-weight: 700; + color: $tx; + margin-bottom: var(--tk-gap-xs); + text-align: center; +} + +.ds-pulse__hint { + font-size: var(--tk-font-body-sm); + color: $tx3; + text-align: center; +} + +@keyframes ds-pulse-ring { + 0% { transform: scale(0.8); opacity: 0.6; } + 50% { transform: scale(1.3); opacity: 0; } + 100% { transform: scale(0.8); opacity: 0; } +} + +@keyframes ds-pulse-dot { + 0%, 100% { transform: scale(1); } + 50% { transform: scale(1.1); } +} + +// ─── 连接动画 ─── +.ds-connect-anim { + position: relative; + width: 100px; + height: 100px; + margin-bottom: 28px; +} + +.ds-connect-anim__ring { + position: absolute; + top: 0; + left: 0; + width: 100px; + height: 100px; + border-radius: 50%; + border: 3px solid $bd-l; + border-top-color: $pri; + animation: ds-connect-spin 1s linear infinite; +} + +.ds-connect-anim__center { + position: absolute; + top: 20px; + left: 20px; + width: 60px; + height: 60px; + border-radius: 50%; + background: $pri-l; + @include flex-center; +} + +.ds-connect-anim__bt { + font-size: 18px; + font-weight: 700; + color: $pri; + font-family: Georgia, 'Times New Roman', serif; +} + +.ds-connect-anim__title { + font-family: Georgia, 'Times New Roman', serif; + font-size: var(--tk-font-body-lg); + font-weight: 700; + color: $tx; + margin-bottom: 6px; + text-align: center; +} + +.ds-connect-anim__sub { + font-size: var(--tk-font-body-sm); + color: $tx3; + text-align: center; +} + +@keyframes ds-connect-spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} + +// ─── 步骤指示器 ─── +.ds-steps { + display: flex; + align-items: center; + gap: 8px; + margin-top: var(--tk-gap-xl); +} + +.ds-steps__dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: $bd; + + &--done { background: $acc; } + &--active { + background: $pri; + animation: ds-pulse-dot 1s ease-in-out infinite; + } +} + +.ds-steps__label { + font-size: var(--tk-font-cap); + color: $tx3; + + &--done { color: $tx3; } + &--active { color: $pri; font-weight: 500; } +} + +.ds-steps__line { + width: 24px; + height: 1px; + background: $bd; + + &--active { background: $pri; } +} + +// ─── 已连接状态卡 ─── +.ds-connected-status { + background: linear-gradient(135deg, $acc 0%, $acc-d 100%); + border-radius: $r; + padding: var(--tk-gap-md); + display: flex; + align-items: center; + gap: 12px; + margin-bottom: var(--tk-gap-md); +} + +.ds-connected-status__icon { + width: 40px; + height: 40px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.2); + @include flex-center; + flex-shrink: 0; +} + +.ds-connected-status__bt { + font-size: 14px; + font-weight: 700; + color: $white; + font-family: Georgia, 'Times New Roman', serif; +} + +.ds-connected-status__info { + flex: 1; +} + +.ds-connected-status__name { + font-size: var(--tk-font-body); + font-weight: 600; + color: $white; +} + +.ds-connected-status__sub { + font-size: var(--tk-font-cap); + color: rgba(255, 255, 255, 0.7); + margin-top: 2px; +} + +.ds-connected-status__badge { + background: rgba(255, 255, 255, 0.2); + border-radius: $r-xs; + padding: 4px 10px; + font-size: var(--tk-font-cap); + color: $white; +} + +// ─── 最新读数卡片 ─── +.ds-latest-reading { + margin-bottom: var(--tk-gap-md) !important; +} + +.ds-latest-reading__icon-wrap { + width: 52px; + height: 52px; + border-radius: $r-sm; + @include flex-center; + flex-shrink: 0; + + &--heart { + background: rgba($dan, 0.06); + } +} + +.ds-latest-reading__heart { + font-size: 28px; + color: $dan; +} + +.ds-latest-reading__body { + flex: 1; + margin-left: var(--tk-gap-md); +} + +.ds-latest-reading__label { + display: block; + font-size: var(--tk-font-cap); + color: $tx3; +} + +.ds-latest-reading__values { + display: flex; + align-items: baseline; + gap: 4px; + margin-top: 4px; +} + +.ds-latest-reading__num { + font-family: Georgia, 'Times New Roman', serif; + font-size: 36px; + font-weight: 700; + color: $tx; + @include serif-number; +} + +.ds-latest-reading__unit { + font-size: var(--tk-font-body-sm); + color: $tx3; +} + +// ─── 历史读数 ─── +.ds-history { + margin-bottom: var(--tk-gap-md); +} + +.ds-history__title { + display: block; + font-size: var(--tk-font-body-sm); + font-weight: 600; + color: $tx; + margin-bottom: var(--tk-gap-sm); + padding-left: 2px; +} + +.ds-history__list { background: $card; border-radius: $r-sm; - padding: var(--tk-gap-lg); - margin-bottom: var(--tk-gap-md); + overflow: hidden; box-shadow: $shadow-sm; } -.sync-reading-item { +.ds-history__row { display: flex; - justify-content: space-between; align-items: center; - padding: var(--tk-gap-sm) 0; + padding: 12px var(--tk-gap-md); border-bottom: 1px solid $bd-l; - &:last-child { + &--last { border-bottom: none; } } -.sync-reading-type { - font-size: var(--tk-font-h1); +.ds-history__type { + width: 90px; + font-size: var(--tk-font-body-sm); color: $tx2; } -.sync-reading-value { - font-size: var(--tk-font-body-lg); - font-weight: bold; - color: var(--tk-pri); +.ds-history__val-wrap { + flex: 1; + display: flex; + align-items: baseline; + gap: 3px; +} + +.ds-history__val { + font-family: Georgia, 'Times New Roman', serif; + font-size: 20px; + font-weight: 700; + color: $tx; @include serif-number; } -.sync-readings-count { - display: block; - margin-top: var(--tk-gap-sm); - font-size: var(--tk-font-body); - color: var(--tk-text-secondary); - text-align: center; +.ds-history__unit { + font-size: var(--tk-font-cap); + color: $tx3; } -.sync-actions-row { +.ds-history__count { + display: block; + text-align: center; + margin-top: var(--tk-gap-sm); + font-size: var(--tk-font-cap); + color: $tx3; +} + +// ─── 操作按钮 ─── +.ds-actions { display: flex; gap: var(--tk-gap-sm); + margin-top: var(--tk-section-gap); } -.sync-error { - margin: var(--tk-gap-lg); - padding: var(--tk-section-gap) var(--tk-gap-lg); +.ds-actions__upload { + flex: 1; + background: $pri; + border-radius: $r-sm; + padding: 14px; + @include flex-center; + box-shadow: $shadow-btn; +} + +.ds-actions__upload-text { + color: $white; + font-size: var(--tk-font-body-lg); + font-weight: 600; +} + +.ds-actions__disconnect { + width: 52px; background: $dan-l; border-radius: $r-sm; -} - -.sync-error-text { - font-size: var(--tk-font-h1); - color: $dan; -} - -.sync-loading { @include flex-center; - padding: 64px 24px; } -.sync-loading-text { - font-size: var(--tk-font-body-lg); - color: $tx2; +.ds-actions__disconnect-icon { + font-size: 16px; + color: $dan; + font-weight: 700; } -.sync-result-card { +// ─── 同步完成 ─── +.ds-done { + width: 100%; display: flex; flex-direction: column; align-items: center; - margin-bottom: var(--tk-gap-lg); - box-shadow: $shadow-sm; + padding: 0 var(--tk-gap-lg); } -.sync-result-icon { +.ds-done__icon { width: 80px; height: 80px; border-radius: 50%; background: $acc-l; @include flex-center; - color: $acc; - font-family: 'Georgia', 'Times New Roman', serif; - font-size: var(--tk-font-num-lg); - font-weight: bold; - margin-bottom: var(--tk-gap-md); + margin-bottom: var(--tk-gap-xl); } -.sync-result-title { - @include section-title; +.ds-done__check { + font-size: 32px; + color: $acc; + font-weight: 700; +} + +.ds-done__title { + font-family: Georgia, 'Times New Roman', serif; + font-size: var(--tk-font-h1); + font-weight: 700; + color: $tx; margin-bottom: var(--tk-gap-xs); } -.sync-result-count { - font-size: var(--tk-font-h1); +.ds-done__desc { + font-size: var(--tk-font-body-sm); + color: $tx3; + text-align: center; + margin-bottom: var(--tk-gap-lg); +} + +.ds-done__stats { + display: flex; + gap: 12px; + width: 100%; + margin-bottom: var(--tk-gap-xl); +} + +.ds-done__stat { + flex: 1; + background: $card; + border-radius: $r-sm; + padding: var(--tk-gap-md); + text-align: center; + border: 1px solid $bd-l; +} + +.ds-done__stat-num { + display: block; + font-family: Georgia, 'Times New Roman', serif; + font-size: var(--tk-font-num); + font-weight: 700; + color: $tx; + + &--pri { color: $pri; } + &--acc { color: $acc; font-size: var(--tk-font-body-lg); } +} + +.ds-done__stat-label { + display: block; + font-size: var(--tk-font-cap); + color: $tx3; + margin-top: 4px; +} + +// ─── 错误页面 ─── +.ds-error-page { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + padding: 0 var(--tk-gap-lg); +} + +.ds-error-page__icon { + width: 80px; + height: 80px; + border-radius: 50%; + background: $dan-l; + @include flex-center; + margin-bottom: var(--tk-gap-xl); +} + +.ds-error-page__x { + font-size: 28px; + color: $dan; + font-weight: 700; +} + +.ds-error-page__title { + font-family: Georgia, 'Times New Roman', serif; + font-size: var(--tk-font-h2); + font-weight: 700; + color: $tx; + margin-bottom: var(--tk-gap-xs); +} + +.ds-error-page__desc { + font-size: var(--tk-font-body-sm); + color: $tx3; + text-align: center; + max-width: 260px; + margin-bottom: var(--tk-gap-lg); +} + +.ds-error-page__detail { + width: 100%; + background: $card; + border-radius: $r-sm; + padding: var(--tk-gap-md); + border: 1px solid $bd-l; + margin-bottom: var(--tk-gap-lg); +} + +.ds-error-page__detail-title { + display: flex; + align-items: center; + gap: 8px; + font-size: var(--tk-font-cap); + font-weight: 500; + color: $tx; + margin-bottom: 12px; +} + +.ds-error-page__detail-row { + display: flex; + justify-content: space-between; + padding: 4px 0; + margin-bottom: 4px; + + &--last { + margin-bottom: 0; + } +} + +.ds-error-page__detail-label { + font-size: var(--tk-font-cap); + color: $tx3; +} + +.ds-error-page__detail-value { + font-size: var(--tk-font-cap); + color: $tx; +} + +.ds-error-page__back { + width: 100%; + border-radius: $r-sm; + padding: 14px; + @include flex-center; + margin-top: 10px; + border: 1px solid $bd; +} + +.ds-error-page__back-text { + color: $tx2; + font-size: var(--tk-font-body); + font-weight: 500; +} + +// ─── 加载态 ─── +.ds-loading { + @include flex-center; + flex-direction: column; + padding: 64px 24px; + gap: var(--tk-gap-md); +} + +.ds-loading__spinner { + width: 40px; + height: 40px; + border-radius: 50%; + border: 3px solid $bd-l; + border-top-color: $pri; + animation: ds-connect-spin 1s linear infinite; +} + +.ds-loading__text { + font-size: var(--tk-font-body-lg); color: $tx2; } diff --git a/apps/miniprogram/src/pages/pkg-health/device-sync/index.tsx b/apps/miniprogram/src/pages/pkg-health/device-sync/index.tsx index 25b49d3..3445090 100644 --- a/apps/miniprogram/src/pages/pkg-health/device-sync/index.tsx +++ b/apps/miniprogram/src/pages/pkg-health/device-sync/index.tsx @@ -6,7 +6,7 @@ import { BLEManager } from '@/services/ble/BLEManager'; import { XiaomiBandAdapter } from '@/services/ble/adapters/XiaomiBandAdapter'; import { BloodPressureAdapter } from '@/services/ble/adapters/BloodPressureAdapter'; import { GlucoseMeterAdapter } from '@/services/ble/adapters/GlucoseMeterAdapter'; -import { CustomBandAdapter } from '@/services/ble/adapters/GenericBleAdapter'; +import { CustomBandAdapter, HuaweiBandAdapter, FallbackAdapter } from '@/services/ble/adapters/GenericBleAdapter'; import { DataSyncScheduler } from '@/services/ble/DataSyncScheduler'; import { uploadReadings } from '@/services/device-sync'; import { useAuthStore } from '@/stores/auth'; @@ -14,12 +14,58 @@ import type { BLEDevice, NormalizedReading } from '@/services/ble/types'; import { useElderClass } from '@/hooks/useElderClass'; import PageShell from '@/components/ui/PageShell'; import ContentCard from '@/components/ui/ContentCard'; +import PrimaryButton from '@/components/ui/PrimaryButton'; import './index.scss'; -/** liveReadings 最大保留条数,防止内存无限增长 */ const MAX_LIVE_READINGS = 200; -type PageState = 'idle' | 'scanning' | 'connecting' | 'connected' | 'syncing' | 'done' | 'error'; +type PageState = 'idle' | 'scanning' | 'found' | 'connecting' | 'connected' | 'syncing' | 'done' | 'error'; + +const DEVICE_TYPE_MAP: Record = { + heart_rate: { label: '心率', unit: 'bpm' }, + blood_pressure: { label: '血压', unit: 'mmHg' }, + blood_glucose: { label: '血糖', unit: 'mmol/L' }, + blood_oxygen: { label: '血氧', unit: '%' }, + temperature: { label: '体温', unit: '°C' }, + steps: { label: '步数', unit: '步' }, + sleep: { label: '睡眠', unit: 'h' }, + stress: { label: '压力', unit: '' }, +}; + +function formatReadingValue(r: NormalizedReading): string { + if (r.device_type === 'heart_rate' && typeof r.values.heart_rate === 'number') { + return String(r.values.heart_rate); + } + if (r.device_type === 'blood_pressure') { + if (typeof r.values.systolic === 'number' && typeof r.values.diastolic === 'number') { + return `${r.values.systolic}/${r.values.diastolic}`; + } + if (r.metric === 'systolic' && typeof r.values.value === 'number') return String(r.values.value); + if (r.metric === 'diastolic' && typeof r.values.value === 'number') return String(r.values.value); + } + if (r.device_type === 'blood_glucose' && typeof r.values.blood_glucose === 'number') { + return String(r.values.blood_glucose); + } + if (typeof r.values.value === 'number') return String(r.values.value); + return '--'; +} + +function getReadingUnit(r: NormalizedReading): string { + const mapped = DEVICE_TYPE_MAP[r.device_type]; + if (mapped) return mapped.unit; + return typeof r.values.unit === 'string' ? r.values.unit : ''; +} + +function getReadingLabel(r: NormalizedReading): string { + const mapped = DEVICE_TYPE_MAP[r.device_type]; + if (!mapped) return r.device_type; + if (r.device_type === 'blood_pressure') { + if (r.metric === 'systolic') return '收缩压'; + if (r.metric === 'diastolic') return '舒张压'; + return '血压'; + } + return mapped.label; +} export default function DeviceSync() { const modeClass = useElderClass(); @@ -35,15 +81,14 @@ export default function DeviceSync() { const [lastSyncAt, setLastSyncAt] = useState(null); const [pendingCount, setPendingCount] = useState(0); - const scheduler = useMemo(() => new DataSyncScheduler({ - intervalMs: 60 * 60 * 1000, - }), []); + const scheduler = useMemo(() => new DataSyncScheduler({ intervalMs: 60 * 60 * 1000 }), []); const bleManagerRef = useRef(null); const getBleManager = useCallback(() => { if (!bleManagerRef.current) { const mgr = new BLEManager({ scanTimeout: 10000, retryCount: 3 }); mgr.registerAdapter(XiaomiBandAdapter); + mgr.registerAdapter(HuaweiBandAdapter); mgr.registerAdapter(BloodPressureAdapter); mgr.registerAdapter(GlucoseMeterAdapter); mgr.registerAdapter(CustomBandAdapter); @@ -53,7 +98,12 @@ export default function DeviceSync() { }, []); useThrottledDidShow(() => { - const bleManager = getBleManager(); + let bleManager: BLEManager; + try { + bleManager = getBleManager(); + } catch { + return; + } bleManager.setOnConnectionChange(() => {}); bleManager.setOnReadings((readings) => { setLiveReadings((prev) => { @@ -61,17 +111,8 @@ export default function DeviceSync() { return merged.length > MAX_LIVE_READINGS ? merged.slice(-MAX_LIVE_READINGS) : merged; }); }); - - // 显示上次同步时间 setLastSyncAt(scheduler.getLastSyncAt()); - // 检查是否有未上传的缓冲数据 - const buffer = (bleManager as unknown as { dataBuffer?: Map }).dataBuffer; - if (buffer) { - setPendingCount(buffer.size); - } - - // 自动同步:超过间隔时尝试上传缓冲数据 if (currentPatient && scheduler.needsSync()) { scheduler.tryAutoSync(async () => { const count = await bleManager.flushPendingReadings(async (readings) => { @@ -95,18 +136,23 @@ export default function DeviceSync() { }, [scheduler]); const handleScan = useCallback(async () => { + console.log('[device-sync] 用户点击扫描按钮'); setPageState('scanning'); setDevices([]); setErrorMsg(''); try { const found = await getBleManager().scanDevices(); - setDevices(found); - if (found.length === 0) { - setErrorMsg('未发现支持的设备,请确认设备已开启蓝牙并靠近手机'); - } - setPageState('idle'); + console.log('[device-sync] 扫描返回设备数:', found.length); + // 未匹配适配器的设备分配 FallbackAdapter(尝试标准健康协议) + const withFallback = found.map((d) => + d.adapter ? d : { ...d, adapter: FallbackAdapter }, + ); + setDevices(withFallback); + setPageState('found'); } catch (e: unknown) { - setErrorMsg(e instanceof Error ? e.message : '扫描失败'); + const msg = e instanceof Error ? e.message : '扫描失败'; + console.error('[device-sync] 扫描异常:', msg); + setErrorMsg(msg); setPageState('error'); } }, []); @@ -126,33 +172,22 @@ export default function DeviceSync() { const handleSync = useCallback(async () => { if (!currentPatient || !selectedDevice) return; - setPageState('syncing'); setErrorMsg(''); - try { const result = await getBleManager().syncToServer(async (readings) => { - return uploadReadings( - currentPatient.id, - selectedDevice.deviceId, - selectedDevice.name, - readings, - ); + return uploadReadings(currentPatient.id, selectedDevice.deviceId, selectedDevice.name, readings); }); - if (result.success) { setSyncCount(result.uploadedCount); setLastSyncAt(Date.now()); setPageState('done'); - - // 如果从体征录入页跳转而来,将最新读数写入 storage 供回填 if (returnTo === 'input' && liveReadings.length > 0) { const mapped: Record = {}; for (const r of liveReadings) { if (r.device_type === 'blood_pressure') { if (r.metric === 'systolic' && typeof r.values.value === 'number') mapped.systolic = r.values.value; if (r.metric === 'diastolic' && typeof r.values.value === 'number') mapped.diastolic = r.values.value; - // 兼容 values 中直接包含 systolic/diastolic 的格式 if (typeof r.values.systolic === 'number') mapped.systolic = r.values.systolic as number; if (typeof r.values.diastolic === 'number') mapped.diastolic = r.values.diastolic as number; } else if (r.device_type === 'blood_glucose' && typeof r.values.blood_glucose === 'number') { @@ -184,141 +219,325 @@ export default function DeviceSync() { setErrorMsg(''); }, []); - const renderIdle = () => ( - - - D - 设备同步 - 连接智能手环、血压计、血糖仪,自动采集健康数据 + const latestReading = liveReadings.length > 0 ? liveReadings[liveReadings.length - 1] : null; + + // ── 渲染子区域 ── + + const renderHero = () => ( + + + BT - - {(lastSyncAt || pendingCount > 0) && ( - - {lastSyncAt && ( - - 上次同步: {new Date(lastSyncAt).toLocaleTimeString()} - - )} - {pendingCount > 0 && ( - - {pendingCount} 条数据待上传 - - )} - - )} - - - 扫描设备 - - - {devices.length > 0 && ( - - 发现的设备 - {devices.map((d) => ( - handleConnect(d)} - > - - {d.name} - {d.adapter?.name} - - 信号 {d.RSSI > -60 ? '强' : d.RSSI > -80 ? '中' : '弱'} - - ))} - - )} + 智能设备同步 + 连接蓝牙设备,自动采集健康数据 ); - const renderConnected = () => ( - - - - 已连接: {selectedDevice?.name} - + const renderDeviceTypes = () => ( + + 支持的设备 + + 心率手环 + 血压计 + 血糖仪 + + + ); - {liveReadings.length > 0 && ( - - 实时数据 - {liveReadings.slice(-5).reverse().map((r, i) => ( - - - {r.device_type === 'heart_rate' ? '心率' - : r.device_type === 'blood_pressure' ? `血压(${r.metric === 'systolic' ? '收缩压' : r.metric === 'diastolic' ? '舒张压' : 'MAP'})` - : r.device_type === 'blood_glucose' ? '血糖' - : r.device_type} - - - {r.device_type === 'heart_rate' - ? `${r.values.heart_rate} bpm` - : r.metric - ? `${r.values.value} ${r.values.unit}` - : JSON.stringify(r.values)} - + const renderLastSync = () => { + if (!lastSyncAt && pendingCount === 0) return null; + return ( + + + + + + + 上次同步 + {lastSyncAt && {new Date(lastSyncAt).toLocaleTimeString()}} + + {pendingCount > 0 && ( + {pendingCount} 条待上传 + )} + + + ); + }; + + const renderPendingWarning = () => { + if (pendingCount <= 0) return null; + return ( + + ! + {pendingCount} 条数据待上传 + + ); + }; + + const renderScanButton = () => ( + + + 扫描附近设备 + + + ); + + const renderDeviceList = () => { + if (pageState !== 'found') return null; + if (devices.length === 0) { + return ( + + + ! + 未发现设备 + 请确认设备已开机且蓝牙已开启,并靠近手机后重试 + + + 重新扫描 + + + ); + } + return ( + + + 发现 {devices.length} 台设备 + 重新扫描 + + {devices.map((d) => { + const isFallback = d.adapter?.name === '通用设备'; + return ( + handleConnect(d)}> + + BT + + + {d.name} + {d.adapter?.name}{isFallback ? ' · 尝试标准协议' : ''} + + + {[4, 7, 10, 13].map((h, i) => ( + -60 ? 4 : d.RSSI > -80 ? 3 : d.RSSI > -90 ? 2 : 1) ? 'ds-signal-bar--active' : ''}`} + style={{ height: `${h}px` }} + /> + ))} + + + + ); + })} + + ? + + 没有找到你的设备? + 确保设备已开机且蓝牙已开启 + + + + ); + }; + + const renderLoading = (text: string) => ( + + + {text} + + ); + + const renderConnectedStatus = () => ( + + + BT + + + {selectedDevice?.name} + 已连接 · 正在采集数据 + + 实时 + + ); + + const renderLatestReading = () => { + if (!latestReading) return null; + return ( + + + + + + {getReadingLabel(latestReading)} · 刚刚 + + {formatReadingValue(latestReading)} + {getReadingUnit(latestReading)} + + + + ); + }; + + const renderReadingsHistory = () => { + if (liveReadings.length <= 1) return null; + const history = liveReadings.slice(0, -1).reverse().slice(0, 5); + return ( + + 历史读数 + + {history.map((r, i) => ( + + {getReadingLabel(r)} + + {formatReadingValue(r)} + {getReadingUnit(r)} + ))} - - 已采集 {liveReadings.length} 条数据 - - )} + 已采集 {liveReadings.length} 条数据 + + ); + }; - - - 上传数据 - - - 断开连接 - + const renderConnectedActions = () => ( + + + 上传数据 + + + ); const renderDone = () => ( - - - V - 同步完成 - 成功上传 {syncCount} 条数据 - - { - handleDisconnect(); - if (returnTo === 'input') { - Taro.navigateBack(); - } - }}> - {returnTo === 'input' ? '返回录入' : '完成'} + + + + + 同步完成 + 数据已安全上传至健康管理平台 + + + {syncCount} + 上传条数 + + + {new Set(liveReadings.map((r) => r.device_type)).size} + 数据类型 + + + 100% + 成功率 + + + { handleDisconnect(); if (returnTo === 'input') Taro.navigateBack(); }}> + {returnTo === 'input' ? '返回录入' : '完成'} + + + ); + + const renderError = () => ( + + + + + 连接失败 + {errorMsg || '无法连接到设备,请检查设备是否在范围内并重试'} + + 错误详情 + 设备{selectedDevice?.name || '--'} + 时间{new Date().toLocaleTimeString()} + + 重新扫描 + Taro.navigateBack()}> + 返回 ); + // ── 主渲染 ── return ( - - - 设备同步 - - - {errorMsg && ( - - {errorMsg} + + {/* 空闲态 */} + {pageState === 'idle' && ( + + {renderHero()} + {renderDeviceTypes()} + {renderLastSync()} + {renderPendingWarning()} + {renderScanButton()} )} - {(pageState === 'scanning' || pageState === 'connecting' || pageState === 'syncing') && ( - - - {pageState === 'scanning' && '正在扫描设备...'} - {pageState === 'connecting' && '正在连接设备...'} - {pageState === 'syncing' && '正在上传数据...'} - + {/* 扫描结果(设备列表或空结果提示) */} + {pageState === 'found' && ( + + {renderHero()} + {renderDeviceTypes()} + {renderDeviceList()} )} - {(pageState === 'idle' || pageState === 'error') && renderIdle()} - {pageState === 'connected' && renderConnected()} - {pageState === 'done' && renderDone()} + {/* 扫描中 */} + {pageState === 'scanning' && ( + + + + + + BT + + + 正在搜索设备... + 请确保设备已开启蓝牙并靠近手机 + + )} + + {/* 连接中 */} + {pageState === 'connecting' && ( + + + + + BT + + + 正在连接 {selectedDevice?.name} + 正在进行蓝牙配对... + + + 发现设备 + + + 连接中 + + + 同步数据 + + + )} + + {/* 同步中 */} + {pageState === 'syncing' && renderLoading('正在上传数据...')} + + {/* 已连接 */} + {pageState === 'connected' && ( + + {renderConnectedStatus()} + {renderLatestReading()} + {renderReadingsHistory()} + {renderConnectedActions()} + + )} + + {/* 同步完成 */} + {pageState === 'done' && {renderDone()}} + + {/* 错误态 */} + {pageState === 'error' && errorMsg && ( + {renderError()} + )} ); } diff --git a/apps/miniprogram/src/pages/pkg-profile/health-records/index.scss b/apps/miniprogram/src/pages/pkg-profile/health-records/index.scss index 9fb1a64..22b9f81 100644 --- a/apps/miniprogram/src/pages/pkg-profile/health-records/index.scss +++ b/apps/miniprogram/src/pages/pkg-profile/health-records/index.scss @@ -1,18 +1,12 @@ @import '../../../styles/variables.scss'; @import '../../../styles/mixins.scss'; -// PageShell 已接管:min-height, background, padding - .page-title { - font-family: 'Georgia', 'Times New Roman', serif; - font-size: var(--tk-font-num); - font-weight: bold; - color: $tx; - margin-bottom: var(--tk-section-gap); - display: block; + @include section-title; padding-left: var(--tk-gap-2xs); } +/* ─── 健康记录卡片 ─── */ .record-list { display: flex; flex-direction: column; @@ -65,3 +59,79 @@ display: block; margin-top: var(--tk-gap-xs); } + +/* ─── 诊断记录卡片 ─── */ +.diagnosis-list { + display: flex; + flex-direction: column; + gap: var(--tk-gap-md); +} + +.diagnosis-card { + background: $card; + border-radius: $r; + padding: var(--tk-card-padding-lg); + box-shadow: $shadow-sm; +} + +.diagnosis-card__header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: var(--tk-gap-xs); +} + +.diagnosis-card__name { + font-size: var(--tk-font-body-lg); + font-weight: bold; + color: $tx; + flex: 1; + margin-right: var(--tk-gap-sm); +} + +.diagnosis-card__status { + font-size: var(--tk-font-cap); + padding: 2px 8px; + border-radius: $r-pill; + font-weight: 600; + + &.active { background: $acc-l; color: $acc; } + &.resolved { background: $bd-l; color: $tx2; } + &.chronic { background: $wrn-l; color: $wrn; } +} + +.diagnosis-card__meta { + display: flex; + gap: var(--tk-gap-sm); + align-items: center; + margin-bottom: var(--tk-gap-2xs); +} + +.diagnosis-card__type { + font-size: var(--tk-font-cap); + padding: 1px 6px; + border-radius: $r-pill; + + &.primary { background: var(--tk-pri-l); color: var(--tk-pri); } + &.secondary { background: $bd-l; color: $tx2; } + &.comorbid { background: $wrn-l; color: $wrn; } +} + +.diagnosis-card__code { + font-size: var(--tk-font-cap); + color: $tx3; + font-variant-numeric: tabular-nums; +} + +.diagnosis-card__date { + font-size: var(--tk-font-cap); + color: $tx3; + display: block; +} + +.diagnosis-card__notes { + font-size: var(--tk-font-body); + color: $tx2; + display: block; + margin-top: var(--tk-gap-xs); +} diff --git a/apps/miniprogram/src/pages/pkg-profile/health-records/index.tsx b/apps/miniprogram/src/pages/pkg-profile/health-records/index.tsx index 8c763c6..1d3bf01 100644 --- a/apps/miniprogram/src/pages/pkg-profile/health-records/index.tsx +++ b/apps/miniprogram/src/pages/pkg-profile/health-records/index.tsx @@ -3,89 +3,197 @@ import { View, Text } from '@tarojs/components'; import Taro, { useReachBottom } from '@tarojs/taro'; import { usePageData } from '@/hooks/usePageData'; import { getCachedPatientId } from '@/services/request'; -import { listHealthRecords, HealthRecord } from '../../../services/health-record'; +import { + listHealthRecords, + HealthRecord, + listDiagnoses, + Diagnosis, +} from '../../../services/health-record'; import EmptyState from '../../../components/EmptyState'; import Loading from '../../../components/Loading'; import { useElderClass } from '../../../hooks/useElderClass'; import PageShell from '@/components/ui/PageShell'; +import SegmentTabs from '../../../components/SegmentTabs'; import './index.scss'; -const TYPE_MAP: Record = { +const TABS = [ + { key: 'records', label: '体检记录' }, + { key: 'diagnoses', label: '诊断记录' }, +] as const; + +const RECORD_TYPE_MAP: Record = { checkup: '体检', follow_up: '复查', referral: '转诊', }; -export default function HealthRecords() { - const modeClass = useElderClass(); - const [records, setRecords] = useState([]); - const [page, setPage] = useState(1); - const [total, setTotal] = useState(0); - const [loading, setLoading] = useState(false); - const [hasPatient, setHasPatient] = useState(true); +const DIAG_TYPE_MAP: Record = { + primary: { label: '主要', cls: 'primary' }, + secondary: { label: '次要', cls: 'secondary' }, + comorbid: { label: '合并症', cls: 'comorbid' }, +}; - const fetchData = useCallback(async (p: number, append = false) => { +const DIAG_STATUS_MAP: Record = { + active: { label: '活动', cls: 'active' }, + resolved: { label: '已解决', cls: 'resolved' }, + chronic: { label: '慢性', cls: 'chronic' }, +}; + +type TabKey = 'records' | 'diagnoses'; + +export default function HealthArchive() { + const modeClass = useElderClass(); + const [tab, setTab] = useState('records'); + + // --- 健康记录 --- + const [records, setRecords] = useState([]); + const [recordsPage, setRecordsPage] = useState(1); + const [recordsTotal, setRecordsTotal] = useState(0); + const [recordsLoading, setRecordsLoading] = useState(false); + + const fetchRecords = useCallback(async (p: number, append = false) => { const patientId = getCachedPatientId(); - if (!patientId) { - setRecords([]); - setHasPatient(false); - return; - } - setHasPatient(true); - setLoading(true); + if (!patientId) return; + setRecordsLoading(true); try { const res = await listHealthRecords(patientId, { page: p, page_size: 20 }); const list = res.data || []; setRecords(append ? (prev) => [...prev, ...list] : list); - setTotal(res.total); - setPage(p); + setRecordsTotal(res.total); + setRecordsPage(p); } catch (err) { console.warn('[health-records] 加载失败:', err); Taro.showToast({ title: '加载失败', icon: 'none' }); } finally { - setLoading(false); + setRecordsLoading(false); } }, []); - usePageData(async () => { await fetchData(1); }, { throttleMs: 10000, enablePullDown: true }); + // --- 诊断记录 --- + const [diagnoses, setDiagnoses] = useState([]); + const [diagPage, setDiagPage] = useState(1); + const [diagTotal, setDiagTotal] = useState(0); + const [diagLoading, setDiagLoading] = useState(false); + const [diagnosesLoaded, setDiagnosesLoaded] = useState(false); + + const fetchDiagnoses = useCallback(async (p: number, append = false) => { + const patientId = getCachedPatientId(); + if (!patientId) return; + setDiagLoading(true); + try { + const res = await listDiagnoses(patientId, { page: p, page_size: 20 }); + const list = res.data || []; + setDiagnoses(append ? (prev) => [...prev, ...list] : list); + setDiagTotal(res.total); + setDiagPage(p); + setDiagnosesLoaded(true); + } catch (err) { + console.warn('[diagnoses] 加载失败:', err); + Taro.showToast({ title: '加载失败', icon: 'none' }); + } finally { + setDiagLoading(false); + } + }, []); + + const handleRefresh = useCallback(async () => { + if (tab === 'records') { + await fetchRecords(1); + } else { + await fetchDiagnoses(1); + } + }, [tab, fetchRecords, fetchDiagnoses]); + + const handleTabSwitch = (key: TabKey) => { + if (key === tab) return; + setTab(key); + if (key === 'diagnoses' && !diagnosesLoaded) { + fetchDiagnoses(1); + } + }; + + usePageData(handleRefresh, { throttleMs: 10000, enablePullDown: true }); + + const currentLoading = tab === 'records' ? recordsLoading : diagLoading; + const currentItems = tab === 'records' ? records.length : diagnoses.length; + const currentTotal = tab === 'records' ? recordsTotal : diagTotal; useReachBottom(() => { - if (!loading && records.length < total) { - fetchData(page + 1, true); + if (currentLoading || currentItems >= currentTotal) return; + if (tab === 'records') { + fetchRecords(recordsPage + 1, true); + } else { + fetchDiagnoses(diagPage + 1, true); } }); + const hasPatient = !!getCachedPatientId(); + return ( - 健康记录 + 健康档案 - - {records.map((r) => ( - - - - {TYPE_MAP[r.record_type] || r.record_type} - - {r.record_date} + handleTabSwitch(k as TabKey)} variant="pill" /> + + {tab === 'records' && ( + + {records.map((r) => ( + + + + {RECORD_TYPE_MAP[r.record_type] || r.record_type} + + {r.record_date} + + {r.overall_assessment && ( + {r.overall_assessment} + )} + {r.source && ( + 来源:{r.source} + )} + {r.notes && ( + {r.notes} + )} - {r.overall_assessment && ( - {r.overall_assessment} - )} - {r.source && ( - 来源:{r.source} - )} - {r.notes && ( - {r.notes} - )} - - ))} - - - {records.length === 0 && !loading && ( - + ))} + )} - {loading && } + {tab === 'diagnoses' && ( + + {diagnoses.map((d) => { + const typeInfo = DIAG_TYPE_MAP[d.diagnosis_type] || { label: d.diagnosis_type, cls: '' }; + const statusInfo = DIAG_STATUS_MAP[d.status] || { label: d.status, cls: '' }; + return ( + + + {d.diagnosis_name} + + {statusInfo.label} + + + + + {typeInfo.label} + + {d.icd_code} + + 诊断日期:{d.diagnosed_date} + {d.notes && ( + {d.notes} + )} + + ); + })} + + )} + + {currentItems === 0 && !currentLoading && ( + + )} + + {currentLoading && } ); } diff --git a/apps/miniprogram/src/pages/pkg-profile/reports/index.scss b/apps/miniprogram/src/pages/pkg-profile/reports/index.scss index edd3d26..fae4939 100644 --- a/apps/miniprogram/src/pages/pkg-profile/reports/index.scss +++ b/apps/miniprogram/src/pages/pkg-profile/reports/index.scss @@ -1,13 +1,12 @@ @import '../../../styles/variables.scss'; @import '../../../styles/mixins.scss'; -// PageShell 已接管:min-height, background, padding - .page-title { @include section-title; padding-left: var(--tk-gap-2xs); } +/* ─── 检查报告卡片 ─── */ .report-list { display: flex; flex-direction: column; @@ -80,3 +79,63 @@ display: block; padding-left: 72px; } + +/* ─── AI 分析卡片 ─── */ +.ai-list { + display: flex; + flex-direction: column; + gap: var(--tk-gap-md); +} + +.ai-card { + background: $card; + border-radius: $r; + padding: var(--tk-card-padding-lg); + box-shadow: $shadow-sm; + + &:active { + opacity: var(--tk-touch-feedback-opacity); + } + + &__header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: var(--tk-gap-xs); + } + + &__type { + font-size: var(--tk-font-body-lg); + font-weight: bold; + color: $tx; + flex: 1; + } + + &__status { + font-size: var(--tk-font-cap); + padding: 2px 8px; + border-radius: $r-pill; + font-weight: 600; + + &.completed { background: $acc-l; color: $acc; } + &.streaming { background: var(--tk-pri-l); color: var(--tk-pri); } + &.failed { background: $dan-l; color: $dan; } + &.pending { background: $bd-l; color: $tx2; } + } + + &__footer { + display: flex; + justify-content: space-between; + align-items: center; + } + + &__time { + font-size: var(--tk-font-cap); + color: $tx3; + } + + &__model { + font-size: var(--tk-font-cap); + color: $tx3; + } +} diff --git a/apps/miniprogram/src/pages/pkg-profile/reports/index.tsx b/apps/miniprogram/src/pages/pkg-profile/reports/index.tsx index 90e34df..b5b8736 100644 --- a/apps/miniprogram/src/pages/pkg-profile/reports/index.tsx +++ b/apps/miniprogram/src/pages/pkg-profile/reports/index.tsx @@ -5,104 +5,187 @@ import { safeNavigateTo } from '@/utils/navigate'; import { usePageData } from '@/hooks/usePageData'; import { getCachedPatientId } from '@/services/request'; import { listReports, LabReport } from '../../../services/report'; +import { listAiAnalysis, type AiAnalysisItem } from '../../../services/ai-analysis'; import EmptyState from '../../../components/EmptyState'; import Loading from '../../../components/Loading'; import { useElderClass } from '../../../hooks/useElderClass'; import PageShell from '@/components/ui/PageShell'; +import SegmentTabs from '../../../components/SegmentTabs'; import './index.scss'; +type TabKey = 'reports' | 'ai'; + +const TABS = [ + { key: 'reports', label: '检查报告' }, + { key: 'ai', label: 'AI 解读' }, +] as const; + +const AI_TYPE_LABELS: Record = { + lab_report_interpretation: '化验单解读', + health_trend_analysis: '趋势分析', + personalized_checkup_plan: '体检方案', + report_summary_generation: '报告摘要', +}; + +const AI_STATUS_MAP: Record = { + completed: { text: '已完成', cls: 'completed' }, + streaming: { text: '分析中', cls: 'streaming' }, + failed: { text: '失败', cls: 'failed' }, + pending: { text: '等待中', cls: 'pending' }, +}; + export default function MyReports() { const modeClass = useElderClass(); - const [reports, setReports] = useState([]); - const [page, setPage] = useState(1); - const [total, setTotal] = useState(0); - const [loading, setLoading] = useState(false); - const [hasPatient, setHasPatient] = useState(true); + const [tab, setTab] = useState('reports'); - const fetchData = useCallback(async (p: number, append = false) => { + // --- 检查报告 --- + const [reports, setReports] = useState([]); + const [reportsPage, setReportsPage] = useState(1); + const [reportsTotal, setReportsTotal] = useState(0); + const [reportsLoading, setReportsLoading] = useState(false); + + const fetchReports = useCallback(async (p: number, append = false) => { const patientId = getCachedPatientId(); - if (!patientId) { - setReports([]); - setHasPatient(false); - return; - } - setHasPatient(true); - setLoading(true); + if (!patientId) return; + setReportsLoading(true); try { const res = await listReports(patientId, p); const list = res.data || []; setReports(append ? (prev) => [...prev, ...list] : list); - setTotal(res.total); - setPage(p); + setReportsTotal(res.total); + setReportsPage(p); } catch (err) { console.warn('[reports] 加载报告列表失败:', err); Taro.showToast({ title: '加载失败', icon: 'none' }); } finally { - setLoading(false); + setReportsLoading(false); } }, []); - usePageData(async () => { await fetchData(1); }, { throttleMs: 10000, enablePullDown: true }); + // --- AI 分析 --- + const [aiList, setAiList] = useState([]); + const [aiPage, setAiPage] = useState(1); + const [aiHasMore, setAiHasMore] = useState(true); + const [aiLoading, setAiLoading] = useState(false); + const [aiLoaded, setAiLoaded] = useState(false); + + const fetchAiList = useCallback(async (p: number, append = false) => { + setAiLoading(true); + try { + const res = await listAiAnalysis(p, 20); + const items = res.data || []; + setAiList(append ? (prev) => [...prev, ...items] : items); + setAiPage(p); + setAiHasMore(items.length >= 20); + setAiLoaded(true); + } catch (err) { + console.warn('[ai-report] 加载分析列表失败:', err); + Taro.showToast({ title: '加载失败', icon: 'none' }); + } finally { + setAiLoading(false); + } + }, []); + + const handleRefresh = useCallback(async () => { + if (tab === 'reports') { + await fetchReports(1); + } else { + await fetchAiList(1); + } + }, [tab, fetchReports, fetchAiList]); + + const handleTabSwitch = (key: TabKey) => { + if (key === tab) return; + setTab(key); + if (key === 'ai' && !aiLoaded) { + fetchAiList(1); + } + }; + + usePageData(handleRefresh, { throttleMs: 10000, enablePullDown: true }); + + const currentLoading = tab === 'reports' ? reportsLoading : aiLoading; useReachBottom(() => { - if (!loading && reports.length < total) { - fetchData(page + 1, true); + if (currentLoading) return; + if (tab === 'reports') { + if (reports.length < reportsTotal) fetchReports(reportsPage + 1, true); + } else { + if (aiHasMore) fetchAiList(aiPage + 1, true); } }); - const goToDetail = (id: string) => { - safeNavigateTo(`/pages/pkg-profile/reports/detail/index?id=${id}`); - }; + const hasPatient = !!getCachedPatientId(); - const formatStatus = (report: LabReport) => { + const formatReportStatus = (report: LabReport) => { const items = report.items; if (!items || !Array.isArray(items)) return 'unknown'; const vals = items as Array<{ is_abnormal?: boolean }>; - const hasAbnormal = vals.some((v) => v.is_abnormal); - return hasAbnormal ? 'abnormal' : 'normal'; - }; - - const typeInitial = (type: string) => { - return type ? type.charAt(0) : '报'; + return vals.some((v) => v.is_abnormal) ? 'abnormal' : 'normal'; }; return ( - 检查报告 + 我的报告 - - {reports.map((r) => { - const status = formatStatus(r); - return ( - goToDetail(r.id)} - > - - - - {typeInitial(r.report_type)} + handleTabSwitch(k as TabKey)} variant="pill" /> + + {tab === 'reports' && ( + + {reports.map((r) => { + const status = formatReportStatus(r); + return ( + safeNavigateTo(`/pages/pkg-profile/reports/detail/index?id=${r.id}`)}> + + + + {r.report_type ? r.report_type.charAt(0) : '报'} + + {r.report_type} - {r.report_type} + + {status === 'normal' ? '正常' : status === 'abnormal' ? '异常' : '未知'} + - - {status === 'normal' ? '正常' : status === 'abnormal' ? '异常' : '未知'} - + {r.report_date} - {r.report_date} - - ); - })} - + ); + })} + + )} - {reports.length === 0 && !loading && ( + {tab === 'ai' && ( + + {aiList.map((item) => { + const si = AI_STATUS_MAP[item.status] || { text: item.status, cls: '' }; + return ( + item.status === 'completed' && safeNavigateTo(`/pages/ai-report/detail/index?id=${item.id}`)} + > + + {AI_TYPE_LABELS[item.analysis_type] || item.analysis_type} + {si.text} + + + {new Date(item.created_at).toLocaleString('zh-CN')} + {item.model_used} + + + ); + })} + + )} + + {tab === 'reports' && reports.length === 0 && !reportsLoading && ( )} - - {loading && ( - + {tab === 'ai' && aiList.length === 0 && !aiLoading && ( + )} + + {currentLoading && } ); } diff --git a/apps/miniprogram/src/pages/pkg-profile/settings/index.scss b/apps/miniprogram/src/pages/pkg-profile/settings/index.scss index b443151..56aaf1a 100644 --- a/apps/miniprogram/src/pages/pkg-profile/settings/index.scss +++ b/apps/miniprogram/src/pages/pkg-profile/settings/index.scss @@ -65,3 +65,14 @@ font-family: 'Georgia', 'Times New Roman', serif; flex-shrink: 0; } + +.settings-toggle { + font-size: var(--tk-font-cap); + color: $tx3; + margin-right: var(--tk-gap-xs); + + &.settings-toggle--active { + color: var(--tk-pri); + font-weight: 600; + } +} diff --git a/apps/miniprogram/src/pages/pkg-profile/settings/index.tsx b/apps/miniprogram/src/pages/pkg-profile/settings/index.tsx index d08b63f..b75a85a 100644 --- a/apps/miniprogram/src/pages/pkg-profile/settings/index.tsx +++ b/apps/miniprogram/src/pages/pkg-profile/settings/index.tsx @@ -2,6 +2,7 @@ import { View, Text } from '@tarojs/components'; import Taro from '@tarojs/taro'; import { safeNavigateTo } from '@/utils/navigate'; import { useAuthStore } from '../../../stores/auth'; +import { useUIStore } from '../../../stores/ui'; import { invalidateHeadersCache, clearRequestCache } from '@/services/request'; import { useElderClass } from '../../../hooks/useElderClass'; import PageShell from '@/components/ui/PageShell'; @@ -12,6 +13,8 @@ export default function Settings() { const modeClass = useElderClass(); const logout = useAuthStore((s) => s.logout); const isMedicalStaff = useAuthStore((s) => s.isMedicalStaff); + const mode = useUIStore((s) => s.mode); + const toggleMode = useUIStore((s) => s.toggle); const handleClearCache = async () => { const { confirm } = await Taro.showModal({ @@ -72,6 +75,16 @@ export default function Settings() { 设置 + + + + + 长辈模式 + + {mode === 'elder' ? '已开启' : '未开启'} + + {'>'} + diff --git a/apps/miniprogram/src/services/analytics.ts b/apps/miniprogram/src/services/analytics.ts index f35b1c8..58bcc8d 100644 --- a/apps/miniprogram/src/services/analytics.ts +++ b/apps/miniprogram/src/services/analytics.ts @@ -66,6 +66,7 @@ function persistQueue(): void { } export function trackEvent(event: EventName | string, properties?: Record): void { + if (flushDisabled) return; loadQueue(); const evt: AnalyticsEvent = { event, @@ -89,7 +90,10 @@ export function trackPageView(pageName: string, properties?: Record { + if (flushDisabled) return; loadQueue(); if (memoryQueue.length === 0) return; @@ -99,9 +103,16 @@ export async function flushEvents(): Promise { try { await api.post('/analytics/batch', { events: batch }); - } catch (e) { - // 静默失败,不打印错误避免控制台洪泛 - void e; + } catch (e: unknown) { + const msg = e instanceof Error ? e.message : String(e); + if (msg === '权限不足' || msg === '登录已过期') { + // 权限不足或未认证,停止后续 flush 并丢弃队列 + flushDisabled = true; + memoryQueue = []; + persistQueue(); + return; + } + // 其他错误(网络等)保留队列重试 memoryQueue = [...batch.slice(-MAX_QUEUE_SIZE), ...memoryQueue].slice(-MAX_QUEUE_SIZE); persistQueue(); } @@ -111,3 +122,8 @@ export function getQueueSize(): number { loadQueue(); return memoryQueue.length; } + +/** 登录/切换用户时调用,重新启用 flush */ +export function resetAnalyticsDisabled(): void { + flushDisabled = false; +} diff --git a/apps/miniprogram/src/services/article.ts b/apps/miniprogram/src/services/article.ts index da9a41d..8ad5e21 100644 --- a/apps/miniprogram/src/services/article.ts +++ b/apps/miniprogram/src/services/article.ts @@ -1,3 +1,4 @@ +import Taro from '@tarojs/taro'; import { api } from './request'; export interface Article { @@ -41,6 +42,46 @@ export function buildCategoryTree(flat: ArticleCategory[]): ArticleCategory[] { return roots; } +/** 获取默认 tenant_id(用于公开 API 调用) */ +function getDefaultTenantId(): string { + return Taro.getStorageSync('tenant_id') || process.env.TARO_APP_DEFAULT_TENANT_ID || ''; +} + +// --------------------------------------------------------------------------- +// 公开端点(无需认证,游客可访问) +// --------------------------------------------------------------------------- + +export async function listPublicArticles(params?: { + page?: number; + page_size?: number; + category_id?: string; + tag_id?: string; + keyword?: string; +}) { + const tenantId = getDefaultTenantId(); + return api.get<{ data: Article[]; total: number }>('/public/articles', { + tenant_id: tenantId, + page: params?.page ?? 1, + page_size: params?.page_size ?? 20, + ...params, + }); +} + +export async function listPublicCategories() { + const tenantId = getDefaultTenantId(); + return api.get('/public/article-categories', { + tenant_id: tenantId, + }); +} + +export async function getPublicArticleDetail(id: string) { + return api.get
(`/public/articles/${id}`); +} + +// --------------------------------------------------------------------------- +// 认证端点(需要登录) +// --------------------------------------------------------------------------- + export async function listArticles(params?: { page?: number; page_size?: number; @@ -60,11 +101,6 @@ export async function getArticleDetail(id: string) { return api.get
(`/health/articles/${id}`); } -/** 公开文章详情(无需认证) */ -export async function getPublicArticleDetail(id: string) { - return api.get
(`/public/articles/${id}`); -} - export async function listCategories() { return api.get('/health/article-categories'); } diff --git a/apps/miniprogram/src/services/ble/BLEManager.ts b/apps/miniprogram/src/services/ble/BLEManager.ts index be54e23..9996155 100644 --- a/apps/miniprogram/src/services/ble/BLEManager.ts +++ b/apps/miniprogram/src/services/ble/BLEManager.ts @@ -70,10 +70,13 @@ export class BLEManager { /** 初始化蓝牙适配器 */ async initialize(): Promise { + console.log('[ble] 步骤1: 开始初始化蓝牙适配器...'); try { await Taro.openBluetoothAdapter(); + console.log('[ble] 步骤1: 蓝牙适配器初始化成功'); } catch (e: unknown) { const errMsg = e instanceof Error ? e.message : (e as { errMsg?: string })?.errMsg || '蓝牙初始化失败,请检查蓝牙是否开启'; + console.error('[ble] 步骤1: 蓝牙初始化失败:', errMsg); throw new Error(errMsg); } } @@ -83,38 +86,61 @@ export class BLEManager { await this.initialize(); const discovered = new Map(); + const allModelKeywords = this.adapters.flatMap((a) => a.supportedModels); + + console.log('[ble] 步骤2: 注册的适配器:', this.adapters.map((a) => a.name)); + console.log('[ble] 步骤2: 匹配关键词:', allModelKeywords); + + let scanDeviceCount = 0; const onFound = (res: BLEScanResult) => { - for (const device of res.devices || []) { + const devices = res.devices || []; + scanDeviceCount += devices.length; + + for (const device of devices) { const name = device.name || device.localName || ''; if (!name) continue; const adapter = this.matchAdapter(name); - if (adapter) { - discovered.set(device.deviceId, { - deviceId: device.deviceId, - name, - RSSI: device.RSSI ?? 0, - localName: device.localName, - advertisData: device.advertisData, - adapter, - }); + + // 每个新发现的设备都打印(最多前 30 个避免日志爆炸) + if (discovered.size < 30 && !discovered.has(device.deviceId)) { + console.log(`[ble] 发现设备: "${name}" (RSSI:${device.RSSI ?? '?'}, 匹配:${adapter?.name ?? '无'})`); } + + discovered.set(device.deviceId, { + deviceId: device.deviceId, + name, + RSSI: device.RSSI ?? 0, + localName: device.localName, + advertisData: device.advertisData, + adapter: adapter ?? undefined, + }); } }; Taro.onBluetoothDeviceFound(onFound); - const allServiceUUIDs = this.adapters.flatMap((a) => a.serviceUUIDs); + console.log('[ble] 步骤3: 开始扫描 (超时', this.config.scanTimeout, 'ms)...'); + // 不传 services 参数 — 扫描所有 BLE 设备,避免设备使用私有 UUID 被过滤掉 await Taro.startBluetoothDevicesDiscovery({ allowDuplicatesKey: false, - services: allServiceUUIDs.length > 0 ? allServiceUUIDs : undefined, }); return new Promise((resolve) => { this.scanTimer = setTimeout(async () => { await this.stopScan(); Taro.offBluetoothDeviceFound(onFound); - resolve(Array.from(discovered.values())); + + const results = Array.from(discovered.values()); + console.log('[ble] 步骤4: 扫描结束'); + console.log('[ble] 回调触发设备总数:', scanDeviceCount); + console.log('[ble] 有名称的设备数:', discovered.size); + console.log('[ble] 最终返回设备数:', results.length); + if (results.length > 0) { + console.log('[ble] 设备列表:', results.map((d) => `${d.name} (${d.adapter?.name ?? '无适配器'})`)); + } + + resolve(results); }, this.config.scanTimeout); }); } diff --git a/apps/miniprogram/src/services/ble/adapters/GenericBleAdapter.ts b/apps/miniprogram/src/services/ble/adapters/GenericBleAdapter.ts index 87d79df..48650bd 100644 --- a/apps/miniprogram/src/services/ble/adapters/GenericBleAdapter.ts +++ b/apps/miniprogram/src/services/ble/adapters/GenericBleAdapter.ts @@ -142,4 +142,30 @@ export const CustomBandAdapter = createGenericBleAdapter({ profiles: ['heart_rate', 'health_thermometer'], }); +/** 华为手环/手表 BLE 适配器 */ +export const HuaweiBandAdapter = createGenericBleAdapter({ + name: 'Huawei Band', + supportedModels: [ + 'HUAWEI Band', + 'HUAWEI Watch', + 'Huawei Band', + 'Huawei Watch', + 'HW-B', + 'HUAW', + '华为手环', + '华为手表', + ], + profiles: ['heart_rate', 'health_thermometer'], +}); + +/** + * 万能 fallback 适配器 — 匹配所有有名称的设备 + * 尝试标准 BLE 健康协议(心率/体温/血压),设备不支持的服务会被安全跳过 + */ +export const FallbackAdapter = createGenericBleAdapter({ + name: '通用设备', + supportedModels: [], // 不参与 matchAdapter,仅作为 fallback + profiles: ['heart_rate', 'health_thermometer', 'blood_pressure'], +}); + export default CustomBandAdapter; diff --git a/apps/miniprogram/src/services/ble/adapters/index.ts b/apps/miniprogram/src/services/ble/adapters/index.ts index db7a504..6ed7302 100644 --- a/apps/miniprogram/src/services/ble/adapters/index.ts +++ b/apps/miniprogram/src/services/ble/adapters/index.ts @@ -1,4 +1,4 @@ export { XiaomiBandAdapter } from './XiaomiBandAdapter'; export { BloodPressureAdapter } from './BloodPressureAdapter'; export { GlucoseMeterAdapter } from './GlucoseMeterAdapter'; -export { CustomBandAdapter, createGenericBleAdapter } from './GenericBleAdapter'; +export { CustomBandAdapter, HuaweiBandAdapter, FallbackAdapter, createGenericBleAdapter } from './GenericBleAdapter'; diff --git a/apps/miniprogram/src/services/request.ts b/apps/miniprogram/src/services/request.ts index dc585db..5deb21c 100644 --- a/apps/miniprogram/src/services/request.ts +++ b/apps/miniprogram/src/services/request.ts @@ -22,6 +22,38 @@ const ERROR_CODE_MAP: Record = { CONCURRENCY_CONFLICT: '数据已被其他人修改,请刷新后重试', }; +// --- 网络异常状态感知 --- +// 检测到网络故障后,短时间内抑制后续请求,避免并发请求全部超时产生大量 toast +// 连续失败时指数退避(3s → 6s → 12s → 30s),避免后端不可达时请求洪泛 +const OFFLINE_SUPPRESS_MS = 3000; +const OFFLINE_MAX_MS = 30_000; +let offlineDetectedAt = 0; +let offlineSuppressMs = OFFLINE_SUPPRESS_MS; +let networkToastShown = false; +let consecutiveNetErrors = 0; + +function isOffline(): boolean { + return offlineDetectedAt > 0 && Date.now() - offlineDetectedAt < offlineSuppressMs; +} + +function markOffline(): void { + offlineDetectedAt = Date.now(); + consecutiveNetErrors++; + // 指数退避:连续失败越多,抑制时间越长(3s → 6s → 12s → 30s cap) + offlineSuppressMs = Math.min(OFFLINE_MAX_MS, OFFLINE_SUPPRESS_MS * Math.pow(2, consecutiveNetErrors - 1)); + if (!networkToastShown) { + networkToastShown = true; + Taro.showToast({ title: '网络异常,请检查连接', icon: 'none', duration: 2000 }); + setTimeout(() => { networkToastShown = false; }, offlineSuppressMs); + } +} + +function clearOffline(): void { + offlineDetectedAt = 0; + offlineSuppressMs = OFFLINE_SUPPRESS_MS; + consecutiveNetErrors = 0; +} + function safeGet(key: string): string { return secureGet(key); } @@ -139,6 +171,12 @@ async function request(method: string, path: string, data?: unknown, timeout? let retryCount401 = 0; for (;;) { if (signal?.aborted) throw new Error('请求已取消'); + + // 离线抑制:刚检测到网络故障时,直接跳过请求,避免 9+ 并发请求全部超时 + if (isOffline()) { + throw new Error('网络异常'); + } + if (!bypassLimiter) await limiter.acquire(); try { const headers = await getHeaders(); @@ -153,10 +191,13 @@ async function request(method: string, path: string, data?: unknown, timeout? Taro.showToast({ title: '网络超时,请重试', icon: 'none' }); throw new Error('网络超时'); } - Taro.showToast({ title: '网络异常,请检查连接', icon: 'none' }); + // 网络异常:标记离线 + toast 去重(3 秒内只弹一次) + markOffline(); throw new Error('网络异常'); } + // 请求成功,清除离线标记 + clearOffline(); if (signal?.aborted) throw new Error('请求已取消'); if (res.statusCode === 401) { @@ -181,7 +222,6 @@ async function request(method: string, path: string, data?: unknown, timeout? } if (res.statusCode === 403) { - Taro.showToast({ title: '权限不足', icon: 'none' }); throw new Error('权限不足'); } @@ -275,4 +315,6 @@ export function resetForTesting(): void { headersCacheTs = 0; refreshPromise = null; isLoggingOut = false; + offlineDetectedAt = 0; + networkToastShown = false; } diff --git a/apps/miniprogram/src/stores/auth.ts b/apps/miniprogram/src/stores/auth.ts index 5753c10..f141d86 100644 --- a/apps/miniprogram/src/stores/auth.ts +++ b/apps/miniprogram/src/stores/auth.ts @@ -2,13 +2,14 @@ import { create } from 'zustand'; import Taro from '@tarojs/taro'; import * as authApi from '@/services/auth'; import { secureGet, secureSet, secureRemove } from '@/utils/secure-storage'; -import { clearRequestCache, markLoggingOut, clearLoggingOut, setCachedPatientId } from '@/services/request'; +import { clearRequestCache, invalidateHeadersCache, markLoggingOut, clearLoggingOut, setCachedPatientId } from '@/services/request'; // secureGet 已内置明文键 fallback,无需再手动 fallback function storageGet(key: string): string { return secureGet(key); } import { resetAllStores } from './index'; +import { resetAnalyticsDisabled } from '@/services/analytics'; // --- 内存缓存,避免每次 Tab 切换重复 Storage IPC + JSON.parse --- let cachedUserJson = ''; @@ -142,6 +143,8 @@ export const useAuthStore = create((set, get) => ({ secureSet('tenant_id', user.tenant_id || ''); set({ user, roles, loading: false }); clearLoggingOut(); + invalidateHeadersCache(); + resetAnalyticsDisabled(); get().loadPatients(); return true; } @@ -175,7 +178,8 @@ export const useAuthStore = create((set, get) => ({ secureSet('tenant_id', resp.user?.tenant_id || tenantId); set({ user: resp.user, roles, loading: false }); clearLoggingOut(); - // 登录成功后自动加载患者档案(如果有的话) + invalidateHeadersCache(); + resetAnalyticsDisabled(); get().loadPatients(); return true; } catch (err) { @@ -211,6 +215,8 @@ export const useAuthStore = create((set, get) => ({ secureRemove('wechat_openid'); set({ user: tokenData.user, roles, loading: false }); clearLoggingOut(); + invalidateHeadersCache(); + resetAnalyticsDisabled(); get().loadPatients(); return true; } catch (err: unknown) { diff --git a/apps/miniprogram/src/utils/abort-controller-polyfill.ts b/apps/miniprogram/src/utils/abort-controller-polyfill.ts new file mode 100644 index 0000000..016357e --- /dev/null +++ b/apps/miniprogram/src/utils/abort-controller-polyfill.ts @@ -0,0 +1,57 @@ +/** + * AbortController / AbortSignal polyfill — 微信小程序 JS 运行时 + * + * 微信小程序 JSCore/V8 不提供 AbortController / AbortSignal Web API。 + * usePageData hook 在每个页面挂载时 new AbortController(), + * 缺少 polyfill 会导致 ReferenceError 崩溃,影响全部 ~40 个数据页面。 + * + * 在 app.tsx 首行导入(crypto-polyfill 之后),确保在任何页面代码之前执行。 + * + * 实现了 usePageData / request.ts 所需的完整规范子集: + * - signal.aborted (getter) + * - controller.abort() + * - signal.addEventListener('abort', cb) / removeEventListener + */ + +if (typeof globalThis.AbortController === 'undefined') { + class _AbortSignal { + aborted = false; + private _listeners: Array<() => void> = []; + + addEventListener(type: string, cb: () => void): void { + if (type === 'abort') this._listeners.push(cb); + } + + removeEventListener(_type: string, cb: () => void): void { + this._listeners = this._listeners.filter((fn) => fn !== cb); + } + + /** @internal 触发 abort 事件 */ + _doAbort(): void { + if (this.aborted) return; + this.aborted = true; + const listeners = this._listeners.slice(); + this._listeners = []; + for (const fn of listeners) { + try { + fn(); + } catch { + /* best-effort dispatch */ + } + } + } + } + + class _AbortController { + readonly signal = new _AbortSignal(); + + abort(): void { + this.signal._doAbort(); + } + } + + // @ts-expect-error — polyfill: globalThis 上原本没有 AbortController + globalThis.AbortController = _AbortController; + // @ts-expect-error — polyfill: globalThis 上原本没有 AbortSignal + globalThis.AbortSignal = _AbortSignal; +} diff --git a/apps/web/src/api/health/articles.ts b/apps/web/src/api/health/articles.ts index 06b8e95..61a678a 100644 --- a/apps/web/src/api/health/articles.ts +++ b/apps/web/src/api/health/articles.ts @@ -23,6 +23,7 @@ export interface ArticleListItem { review_note?: string; view_count: number; sort_order: number; + is_public: boolean; published_at?: string; created_at: string; updated_at: string; @@ -43,6 +44,7 @@ export interface CreateArticleReq { category_id?: string; tag_ids?: string[]; sort_order?: number; + is_public?: boolean; } export interface UpdateArticleReq { @@ -55,6 +57,7 @@ export interface UpdateArticleReq { category_id?: string; tag_ids?: string[]; sort_order?: number; + is_public?: boolean; version: number; } diff --git a/apps/web/src/pages/health/articleEditor/ArticleEditor.tsx b/apps/web/src/pages/health/articleEditor/ArticleEditor.tsx index 19b553b..fe6001f 100644 --- a/apps/web/src/pages/health/articleEditor/ArticleEditor.tsx +++ b/apps/web/src/pages/health/articleEditor/ArticleEditor.tsx @@ -45,6 +45,7 @@ export default function ArticleEditor() { const [categoryId, setCategoryId] = useState(undefined); const [selectedTagIds, setSelectedTagIds] = useState([]); const [sortOrder, setSortOrder] = useState(0); + const [isPublic, setIsPublic] = useState(true); const [version, setVersion] = useState(0); // 选项数据 @@ -101,6 +102,7 @@ export default function ArticleEditor() { setCategoryId(article.category_id); setSelectedTagIds(article.tags?.map((t) => t.id) || []); setSortOrder(article.sort_order); + setIsPublic(article.is_public ?? true); setVersion(article.version); } catch { message.error('加载文章失败'); @@ -230,6 +232,7 @@ export default function ArticleEditor() { category_id: categoryId, tag_ids: selectedTagIds, sort_order: sortOrder, + is_public: isPublic, version, }); message.success('文章已保存'); @@ -245,6 +248,7 @@ export default function ArticleEditor() { category_id: categoryId, tag_ids: selectedTagIds, sort_order: sortOrder, + is_public: isPublic, }); message.success('文章已创建'); navigate('/health/articles'); @@ -256,7 +260,7 @@ export default function ArticleEditor() { } }, [ id, isEdit, title, summary, content, coverImage, slug, categoryId, - selectedTagIds, sortOrder, version, navigate, + selectedTagIds, sortOrder, isPublic, version, navigate, ]); const handleSubmit = useCallback(async () => { @@ -277,6 +281,7 @@ export default function ArticleEditor() { category_id: categoryId, tag_ids: selectedTagIds, sort_order: sortOrder, + is_public: isPublic, version, }); const updated = await articleApi.get(id); @@ -292,6 +297,7 @@ export default function ArticleEditor() { category_id: categoryId, tag_ids: selectedTagIds, sort_order: sortOrder, + is_public: isPublic, }); currentVersion = created.version; setVersion(created.version); @@ -312,7 +318,7 @@ export default function ArticleEditor() { } }, [ id, isEdit, title, summary, content, coverImage, slug, categoryId, - selectedTagIds, sortOrder, version, navigate, + selectedTagIds, sortOrder, isPublic, version, navigate, ]); if (loading) { @@ -463,6 +469,8 @@ export default function ArticleEditor() { onSlugChange={setSlug} sortOrder={sortOrder} onSortOrderChange={setSortOrder} + isPublic={isPublic} + onIsPublicChange={setIsPublic} categories={categories} tags={tags} /> diff --git a/apps/web/src/pages/health/articleEditor/ArticleSettingsDrawer.tsx b/apps/web/src/pages/health/articleEditor/ArticleSettingsDrawer.tsx index 994706e..76ca9c7 100644 --- a/apps/web/src/pages/health/articleEditor/ArticleSettingsDrawer.tsx +++ b/apps/web/src/pages/health/articleEditor/ArticleSettingsDrawer.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { Drawer, Input, Select, Space, Upload, Button, message } from 'antd'; +import { Drawer, Input, Select, Space, Upload, Button, Switch, message } from 'antd'; import { UploadOutlined, PictureOutlined } from '@ant-design/icons'; import type { ArticleTagItem } from '../../../api/health/articles'; import { uploadFile } from '../../../api/upload'; @@ -21,6 +21,8 @@ interface ArticleSettingsDrawerProps { onSlugChange: (v: string) => void; sortOrder: number; onSortOrderChange: (v: number) => void; + isPublic: boolean; + onIsPublicChange: (v: boolean) => void; categories: { id: string; name: string }[]; tags: ArticleTagItem[]; } @@ -53,6 +55,8 @@ export default function ArticleSettingsDrawer({ onSlugChange, sortOrder, onSortOrderChange, + isPublic, + onIsPublicChange, categories, tags, }: ArticleSettingsDrawerProps) { @@ -190,6 +194,17 @@ export default function ArticleSettingsDrawer({ placeholder="0" /> + + {/* 公开可见 */} +
+
+ +
+ 开启后游客可在小程序查看此文章 +
+
+ +
diff --git a/crates/erp-health/src/dto/article_dto.rs b/crates/erp-health/src/dto/article_dto.rs index 69962fe..2c2eb07 100644 --- a/crates/erp-health/src/dto/article_dto.rs +++ b/crates/erp-health/src/dto/article_dto.rs @@ -7,6 +7,10 @@ use erp_core::sanitize::{ sanitize_option, sanitize_rich_html_option, sanitize_string, strip_html_tags, }; +const fn default_true() -> bool { + true +} + // --------------------------------------------------------------------------- // 文章 DTOs // --------------------------------------------------------------------------- @@ -29,6 +33,8 @@ pub struct ArticleResp { pub review_note: Option, pub view_count: i32, pub sort_order: i32, + /// 是否公开(游客可访问) + pub is_public: bool, /// 文章关联的分类 ID(来自 article_category 表) pub category_id: Option, /// 文章关联的标签名称列表 @@ -49,6 +55,8 @@ pub struct ArticleListItem { pub published_at: Option>, pub status: String, pub view_count: i32, + /// 是否公开(游客可访问) + pub is_public: bool, /// 分类 ID pub category_id: Option, /// 标签名称列表 @@ -96,6 +104,9 @@ pub struct CreateArticleReq { /// 标签 ID 列表 #[serde(default)] pub tag_ids: Vec, + /// 是否公开(游客可访问),默认 true + #[serde(default = "default_true")] + pub is_public: bool, } impl CreateArticleReq { @@ -134,6 +145,8 @@ pub struct UpdateArticleReq { /// 标签 ID 列表(传入则整体替换) pub tag_ids: Option>, pub sort_order: Option, + /// 是否公开(游客可访问) + pub is_public: Option, pub version: i32, } diff --git a/crates/erp-health/src/entity/article.rs b/crates/erp-health/src/entity/article.rs index d0081ed..a20134f 100644 --- a/crates/erp-health/src/entity/article.rs +++ b/crates/erp-health/src/entity/article.rs @@ -41,6 +41,8 @@ pub struct Model { pub view_count: i32, /// 排序权重 pub sort_order: i32, + /// 是否公开(游客可访问) + pub is_public: bool, pub created_at: DateTimeUtc, pub updated_at: DateTimeUtc, #[sea_orm(skip_serializing_if = "Option::is_none")] diff --git a/crates/erp-health/src/handler/article_category_handler.rs b/crates/erp-health/src/handler/article_category_handler.rs index d7333c1..b42fadb 100644 --- a/crates/erp-health/src/handler/article_category_handler.rs +++ b/crates/erp-health/src/handler/article_category_handler.rs @@ -1,7 +1,7 @@ //! 文章分类 Handler use axum::Extension; -use axum::extract::{FromRef, Json, Path, State}; +use axum::extract::{FromRef, Json, Path, Query, State}; use erp_core::error::AppError; use erp_core::rbac::require_permission; use erp_core::types::{ApiResponse, TenantContext}; @@ -12,6 +12,32 @@ use crate::state::HealthState; use validator::Validate; +// --------------------------------------------------------------------------- +// 公开端点(小程序游客 / 无需认证) +// --------------------------------------------------------------------------- + +#[derive(Debug, serde::Deserialize)] +pub struct PublicCategoryQuery { + pub tenant_id: uuid::Uuid, +} + +/// GET /public/article-categories — 公开分类列表(无需认证) +pub async fn list_public_categories( + State(state): State, + Query(params): Query, +) -> Result>>, AppError> +where + HealthState: FromRef, + S: Clone + Send + Sync + 'static, +{ + let result = article_category_service::list_categories(&state, params.tenant_id).await?; + Ok(Json(ApiResponse::ok(result))) +} + +// --------------------------------------------------------------------------- +// 管理端端点(需要认证) +// --------------------------------------------------------------------------- + pub async fn list_categories( State(state): State, Extension(ctx): Extension, diff --git a/crates/erp-health/src/handler/article_handler.rs b/crates/erp-health/src/handler/article_handler.rs index 2f9782d..0ba76a7 100644 --- a/crates/erp-health/src/handler/article_handler.rs +++ b/crates/erp-health/src/handler/article_handler.rs @@ -45,6 +45,7 @@ where params.category_id, params.tag_id, params.keyword, + None, // 管理端不过滤 is_public ) .await?; Ok(Json(ApiResponse::ok(result))) @@ -69,6 +70,7 @@ pub async fn list_public_articles( params.category_id, params.tag_id, params.keyword, + Some(true), // 公开端点只返回 is_public=true 的文章 ) .await?; Ok(Json(ApiResponse::ok(result))) diff --git a/crates/erp-health/src/module.rs b/crates/erp-health/src/module.rs index a3757ff..f822a27 100644 --- a/crates/erp-health/src/module.rs +++ b/crates/erp-health/src/module.rs @@ -5,7 +5,9 @@ use erp_core::error::AppResult; use erp_core::events::EventBus; use erp_core::module::{ErpModule, PermissionDescriptor}; -use crate::handler::{article_handler, banner_handler, ble_gateway_handler}; +use crate::handler::{ + article_category_handler, article_handler, banner_handler, ble_gateway_handler, +}; pub struct HealthModule; @@ -203,6 +205,10 @@ impl HealthModule { "/public/articles/{id}", axum::routing::get(article_handler::get_public_article), ) + .route( + "/public/article-categories", + axum::routing::get(article_category_handler::list_public_categories), + ) } /// FHIR R4 只读路由(使用 OAuth client_credentials 认证) diff --git a/crates/erp-health/src/service/article_service.rs b/crates/erp-health/src/service/article_service.rs index 363f1d4..95f8a67 100644 --- a/crates/erp-health/src/service/article_service.rs +++ b/crates/erp-health/src/service/article_service.rs @@ -21,7 +21,7 @@ use crate::error::{HealthError, HealthResult}; use crate::service::validation; use crate::state::HealthState; -/// 文章列表(管理端,支持状态/分类/标签/关键词筛选) +/// 文章列表(管理端,支持状态/分类/标签/关键词/公开状态筛选) #[allow(clippy::too_many_arguments)] pub async fn list_articles( state: &HealthState, @@ -33,6 +33,7 @@ pub async fn list_articles( category_id: Option, tag_id: Option, keyword: Option, + is_public: Option, ) -> HealthResult> { let limit = page_size.min(100); let offset = page.saturating_sub(1) * limit; @@ -47,6 +48,9 @@ pub async fn list_articles( if let Some(ref s) = status { query = query.filter(article::Column::Status.eq(s)); } + if let Some(pub_flag) = is_public { + query = query.filter(article::Column::IsPublic.eq(pub_flag)); + } if let Some(cid) = category_id { query = query.filter(article::Column::CategoryId.eq(cid)); } @@ -104,6 +108,7 @@ pub async fn list_articles( published_at: m.published_at, status: m.status, view_count: m.view_count, + is_public: m.is_public, category_id: m.category_id, tags, version: m.version, @@ -374,6 +379,7 @@ pub async fn create_article( review_note: Set(None), view_count: Set(0), sort_order: Set(0), + is_public: Set(req.is_public), created_at: Set(now), updated_at: Set(now), created_by: Set(operator_id), @@ -445,6 +451,9 @@ pub async fn update_article( if let Some(v) = req.sort_order { active.sort_order = Set(v); } + if let Some(v) = req.is_public { + active.is_public = Set(v); + } active.updated_at = Set(Utc::now()); active.updated_by = Set(operator_id); active.version = Set(next_ver); @@ -530,6 +539,7 @@ fn full_model_to_resp(m: article::Model, tags: Vec) -> ArticleResp { review_note: m.review_note, view_count: m.view_count, sort_order: m.sort_order, + is_public: m.is_public, category_id: m.category_id, tags, created_at: m.created_at, diff --git a/crates/erp-server/_server_err3.txt b/crates/erp-server/_server_err3.txt new file mode 100644 index 0000000..9c3a541 --- /dev/null +++ b/crates/erp-server/_server_err3.txt @@ -0,0 +1,3 @@ + Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.81s + Running `G:\hms\target\debug\erp-server.exe` +error: process didn't exit successfully: `G:\hms\target\debug\erp-server.exe` (exit code: 1) diff --git a/crates/erp-server/migration/src/lib.rs b/crates/erp-server/migration/src/lib.rs index 446dfc3..e44caaf 100644 --- a/crates/erp-server/migration/src/lib.rs +++ b/crates/erp-server/migration/src/lib.rs @@ -168,6 +168,7 @@ mod m20260521_000163_reorganize_menus_by_business_flow; mod m20260521_000164_reorganize_menus_scheme_b; mod m20260522_000160_article_add_is_public; mod m20260522_000161_patient_points_manage_perm; +mod m20260522_000162_seed_patient_miniprogram_permissions; pub struct Migrator; @@ -343,6 +344,7 @@ impl MigratorTrait for Migrator { Box::new(m20260521_000164_reorganize_menus_scheme_b::Migration), Box::new(m20260522_000160_article_add_is_public::Migration), Box::new(m20260522_000161_patient_points_manage_perm::Migration), + Box::new(m20260522_000162_seed_patient_miniprogram_permissions::Migration), ] } } diff --git a/crates/erp-server/migration/src/m20260521_000158_alerts_add_source_columns.rs b/crates/erp-server/migration/src/m20260521_000158_alerts_add_source_columns.rs new file mode 100644 index 0000000..abf2eb1 --- /dev/null +++ b/crates/erp-server/migration/src/m20260521_000158_alerts_add_source_columns.rs @@ -0,0 +1,37 @@ +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + // alerts 表新增 source(告警来源)和 original_id(关联原始告警)字段 + manager + .alter_table( + Table::alter() + .table(Alias::new("alerts")) + .add_column( + ColumnDef::new(Alias::new("source")) + .string() + .not_null() + .default("rule_engine"), + ) + .add_column(ColumnDef::new(Alias::new("original_id")).uuid().null()) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .alter_table( + Table::alter() + .table(Alias::new("alerts")) + .drop_column(Alias::new("source")) + .drop_column(Alias::new("original_id")) + .to_owned(), + ) + .await + } +} diff --git a/crates/erp-server/migration/src/m20260521_000159_patient_phone_and_consent_seed.rs b/crates/erp-server/migration/src/m20260521_000159_patient_phone_and_consent_seed.rs new file mode 100644 index 0000000..1515252 --- /dev/null +++ b/crates/erp-server/migration/src/m20260521_000159_patient_phone_and_consent_seed.rs @@ -0,0 +1,108 @@ +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + // 1. patient 表新增 phone 和 phone_hash 字段 + manager + .alter_table( + Table::alter() + .table(Alias::new("patient")) + .add_column(ColumnDef::new(Alias::new("phone")).text().null()) + .add_column(ColumnDef::new(Alias::new("phone_hash")).text().null()) + .to_owned(), + ) + .await?; + + // 2. 为所有现有活跃患者自动授予 data_processing 同意(默认拒绝策略下保持向后兼容) + let seed_consent_sql_1 = r#" + INSERT INTO consent (id, tenant_id, patient_id, consent_type, consent_scope, status, granted_at, consent_method, created_at, updated_at, version) + SELECT + gen_random_uuid(), + p.tenant_id, + p.id, + 'data_processing', + 'all', + 'granted', + NOW(), + 'system_auto', + NOW(), + NOW(), + 1 + FROM patient p + WHERE p.status = 'active' + AND p.deleted_at IS NULL + AND NOT EXISTS ( + SELECT 1 FROM consent c + WHERE c.patient_id = p.id + AND c.tenant_id = p.tenant_id + AND c.consent_type = 'data_processing' + AND c.deleted_at IS NULL + ) + "#; + manager + .get_connection() + .execute_unprepared(seed_consent_sql_1) + .await?; + + // 3. 为所有现有活跃患者自动授予 health_data_collection 同意 + let seed_consent_sql_2 = r#" + INSERT INTO consent (id, tenant_id, patient_id, consent_type, consent_scope, status, granted_at, consent_method, created_at, updated_at, version) + SELECT + gen_random_uuid(), + p.tenant_id, + p.id, + 'health_data_collection', + 'all', + 'granted', + NOW(), + 'system_auto', + NOW(), + NOW(), + 1 + FROM patient p + WHERE p.status = 'active' + AND p.deleted_at IS NULL + AND NOT EXISTS ( + SELECT 1 FROM consent c + WHERE c.patient_id = p.id + AND c.tenant_id = p.tenant_id + AND c.consent_type = 'health_data_collection' + AND c.deleted_at IS NULL + ) + "#; + manager + .get_connection() + .execute_unprepared(seed_consent_sql_2) + .await?; + + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + // 删除系统自动生成的 consent 记录 + let delete_sql = r#" + DELETE FROM consent WHERE consent_method = 'system_auto' + "#; + manager + .get_connection() + .execute_unprepared(delete_sql) + .await?; + + // 移除 phone 和 phone_hash 列 + manager + .alter_table( + Table::alter() + .table(Alias::new("patient")) + .drop_column(Alias::new("phone")) + .drop_column(Alias::new("phone_hash")) + .to_owned(), + ) + .await?; + + Ok(()) + } +} diff --git a/crates/erp-server/migration/src/m20260522_000160_article_add_is_public.rs b/crates/erp-server/migration/src/m20260522_000160_article_add_is_public.rs new file mode 100644 index 0000000..18d899e --- /dev/null +++ b/crates/erp-server/migration/src/m20260522_000160_article_add_is_public.rs @@ -0,0 +1,34 @@ +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .alter_table( + Table::alter() + .table(Alias::new("article")) + .add_column( + ColumnDef::new(Alias::new("is_public")) + .boolean() + .not_null() + .default(true), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .alter_table( + Table::alter() + .table(Alias::new("article")) + .drop_column(Alias::new("is_public")) + .to_owned(), + ) + .await + } +} diff --git a/crates/erp-server/migration/src/m20260522_000162_seed_patient_miniprogram_permissions.rs b/crates/erp-server/migration/src/m20260522_000162_seed_patient_miniprogram_permissions.rs new file mode 100644 index 0000000..8aeb16b --- /dev/null +++ b/crates/erp-server/migration/src/m20260522_000162_seed_patient_miniprogram_permissions.rs @@ -0,0 +1,170 @@ +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let db = manager.get_connection(); + + // 1) 注册 system.analytics.submit 幽灵权限(代码中 require_permission 使用但未注册) + let sys = "00000000-0000-0000-0000-000000000000"; + db.execute_unprepared(&format!( + "INSERT INTO permissions (id, tenant_id, name, code, resource, action, description, created_at, updated_at, created_by, updated_by, deleted_at, version) \ + SELECT gen_random_uuid(), t.id, '提交埋点数据', 'system.analytics.submit', 'system', 'submit', '小程序端埋点数据批量提交', NOW(), NOW(), '{sys}', '{sys}', NULL, 1 \ + FROM tenant t \ + WHERE NOT EXISTS (SELECT 1 FROM permissions p WHERE p.tenant_id = t.id AND p.code = 'system.analytics.submit' AND p.deleted_at IS NULL)" + )).await?; + + // 2) 患者角色缺失的 .manage 权限(小程序端写入操作) + let patient_manage_perms: &[&str] = &[ + // 体征录入 + "health.health-data.manage", + // 日常监测创建 + "health.daily-monitoring.manage", + // 预约创建/取消 + "health.appointment.manage", + // 医生列表(预约选医生) + "health.doctor.list", + // 随访提交 + "health.follow-up.manage", + // 咨询创建/发送消息 + "health.consultation.manage", + // 药物提醒 CRUD + "health.medication-reminders.manage", + // 知情同意授权/撤回 + "health.consent.manage", + // 设备数据上传 + "health.device-readings.manage", + // 患者自更新(绑定手机、自助建档) + "health.patient.manage", + // AI 分析报告查看 + "ai.analysis.list", + // AI 聊天会话列表 + "ai.chat.session.list", + // AI 聊天会话管理 + "ai.chat.session.manage", + // 埋点提交 + "system.analytics.submit", + ]; + + // 为所有租户的 patient 角色批量分配(幂等,data_scope=self) + assign_perms_by_codes(db, "patient", patient_manage_perms).await?; + + // 3) 患者角色缺失的 .list 权限 + let patient_list_perms: &[&str] = &[ + // 化验报告 + 健康记录 + 诊断记录 + 体征列表(共享 health.health-data.list) + "health.health-data.list", + // 行动收件箱(首页工作台) + "health.action-inbox.list", + ]; + + assign_perms_by_codes(db, "patient", patient_list_perms).await?; + + // 4) 为 admin/doctor/nurse/health_manager 角色 also 分配 system.analytics.submit + // 这些角色可能也需要埋点权限 + let analytics_roles: &[&str] = &["admin", "doctor", "nurse", "health_manager"]; + for role in analytics_roles { + assign_single_perm(db, role, "system.analytics.submit").await?; + } + + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let db = manager.get_connection(); + + // 移除 patient 角色新增的权限关联 + let remove_codes: &[&str] = &[ + "health.health-data.manage", + "health.health-data.list", + "health.daily-monitoring.manage", + "health.appointment.manage", + "health.doctor.list", + "health.follow-up.manage", + "health.consultation.manage", + "health.medication-reminders.manage", + "health.consent.manage", + "health.device-readings.manage", + "health.patient.manage", + "ai.analysis.list", + "ai.chat.session.list", + "ai.chat.session.manage", + "system.analytics.submit", + "health.action-inbox.list", + ]; + + let codes_csv: String = remove_codes + .iter() + .map(|c| format!("'{}'", c)) + .collect::>() + .join(","); + + db.execute_unprepared(&format!( + "DELETE FROM role_permissions \ + WHERE role_id IN (SELECT id FROM roles WHERE code = 'patient') \ + AND permission_id IN (SELECT id FROM permissions WHERE code IN ({codes_csv}))" + )) + .await?; + + // 移除其他角色的 system.analytics.submit + let analytics_roles: &[&str] = &["admin", "doctor", "nurse", "health_manager"]; + for role in analytics_roles { + db.execute_unprepared(&format!( + "DELETE FROM role_permissions \ + WHERE role_id IN (SELECT id FROM roles WHERE code = '{role}') \ + AND permission_id IN (SELECT id FROM permissions WHERE code = 'system.analytics.submit')" + )).await?; + } + + // 软删除 system.analytics.submit 权限 + db.execute_unprepared( + "UPDATE permissions SET deleted_at = NOW() WHERE code = 'system.analytics.submit' AND deleted_at IS NULL" + ).await?; + + Ok(()) + } +} + +async fn assign_perms_by_codes( + db: &sea_orm_migration::prelude::SchemaManagerConnection<'_>, + role_code: &str, + perm_codes: &[&str], +) -> Result<(), DbErr> { + let codes_csv: String = perm_codes + .iter() + .map(|c| format!("'{}'", c)) + .collect::>() + .join(","); + + db.execute_unprepared(&format!( + "INSERT INTO role_permissions (role_id, permission_id, tenant_id, data_scope, created_at, updated_at, created_by, updated_by, deleted_at, version) \ + SELECT r.id, p.id, r.tenant_id, 'self', NOW(), NOW(), r.id, r.id, NULL, 1 \ + FROM roles r \ + JOIN permissions p ON p.tenant_id = r.tenant_id AND p.code IN ({codes_csv}) AND p.deleted_at IS NULL \ + WHERE r.code = '{role_code}' AND r.deleted_at IS NULL \ + ON CONFLICT (role_id, permission_id) WHERE deleted_at IS NULL \ + DO UPDATE SET deleted_at = NULL, version = role_permissions.version + 1, updated_at = NOW()" + )).await?; + + Ok(()) +} + +async fn assign_single_perm( + db: &sea_orm_migration::prelude::SchemaManagerConnection<'_>, + role_code: &str, + perm_code: &str, +) -> Result<(), DbErr> { + db.execute_unprepared(&format!( + "INSERT INTO role_permissions (role_id, permission_id, tenant_id, data_scope, created_at, updated_at, created_by, updated_by, deleted_at, version) \ + SELECT r.id, p.id, r.tenant_id, 'all', NOW(), NOW(), r.id, r.id, NULL, 1 \ + FROM roles r \ + JOIN permissions p ON p.tenant_id = r.tenant_id AND p.code = '{perm_code}' AND p.deleted_at IS NULL \ + WHERE r.code = '{role_code}' AND r.deleted_at IS NULL \ + ON CONFLICT (role_id, permission_id) WHERE deleted_at IS NULL \ + DO UPDATE SET deleted_at = NULL, version = role_permissions.version + 1, updated_at = NOW()" + )).await?; + + Ok(()) +} diff --git a/crates/erp-server/tests/integration/health_article_tests.rs b/crates/erp-server/tests/integration/health_article_tests.rs index 70dd038..ece80c0 100644 --- a/crates/erp-server/tests/integration/health_article_tests.rs +++ b/crates/erp-server/tests/integration/health_article_tests.rs @@ -24,6 +24,7 @@ fn default_create_article_req() -> CreateArticleReq { content_type: None, category_id: None, tag_ids: vec![], + is_public: true, } } @@ -206,6 +207,7 @@ async fn test_article_update() { category_id: None, tag_ids: None, sort_order: None, + is_public: None, version: article.version, }, ) @@ -248,6 +250,7 @@ async fn test_article_list_filter() { None, None, None, + None, ) .await .unwrap(); @@ -263,6 +266,7 @@ async fn test_article_list_filter() { None, None, None, + None, ) .await .unwrap(); @@ -417,6 +421,7 @@ async fn test_tag_crud_and_article_association() { content_type: None, category_id: None, sort_order: None, + is_public: None, }, ) .await @@ -489,6 +494,7 @@ async fn test_article_version_conflict() { category_id: None, tag_ids: None, sort_order: None, + is_public: None, }, ) .await @@ -514,6 +520,7 @@ async fn test_article_version_conflict() { category_id: None, tag_ids: None, sort_order: None, + is_public: None, }, ) .await; diff --git a/dev.ps1 b/dev.ps1 index 1bd2730..34928f6 100644 --- a/dev.ps1 +++ b/dev.ps1 @@ -23,10 +23,10 @@ $LogDir = ".logs" $env:ERP__DATABASE__URL = "postgres://postgres:123123@localhost:5432/erp" $env:ERP__JWT__SECRET = "dev-secret-key-change-in-prod" $env:ERP__AUTH__SUPER_ADMIN_PASSWORD = "Admin@2026" -$env:ERP__REDIS__URL = "redis://:NMPjsdx5MTTZyJXQ@129.204.154.246:6379" +$env:ERP__REDIS__URL = "redis://localhost:6379" $env:ERP__WECHAT__APPID = "wx20f4ef9cc2ec66c5" $env:ERP__WECHAT__SECRET = "52679a563af519590e882c4b8d846f7b" -$env:ERP__WECHAT__DEV_MODE = "false" +$env:ERP__WECHAT__DEV_MODE = "true" $env:ERP__HEALTH__AES_KEY = "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2" $env:ERP__HEALTH__HMAC_KEY = "f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5" $env:ERP__RATE_LIMIT__FAIL_CLOSE = "false" diff --git a/docs/audits/v3-beta/01-executive-summary.md b/docs/audits/v3-beta/01-executive-summary.md new file mode 100644 index 0000000..0a67577 --- /dev/null +++ b/docs/audits/v3-beta/01-executive-summary.md @@ -0,0 +1,97 @@ +# HMS V3 Beta 多学科综合测试报告 — 执行摘要 + +> 测试日期: 2026-05-21 | 分支: feat/media-library-banner +> 测试团队: 5 个专家团队并行(Web功能 / 性能兼容 / 小程序 / API / 静态分析) +> 报告版本: v1.0 + +## 1. 测试范围与方法 + +| 维度 | 方法 | 工具 | +|------|------|------| +| Web 前端功能 | 核心业务流程操作 + 边缘场景 | chrome-devtools MCP | +| Web 性能/兼容性 | Lighthouse + Core Web Vitals + 5 种视口 | chrome-devtools MCP | +| 小程序功能 | 5 Tab 页 + 核心功能 + API 验证 | weapp-local MCP | +| API 端点 | 69 个测试用例(CRUD/权限/注入/边界值) | curl/Bash | +| 静态代码分析 | TypeScript 类型/安全/性能反模式 | Grep/Read/Bash | + +## 2. 总体评估 + +| 指标 | 值 | +|------|-----| +| **综合质量评级** | **B- (6.5/10)** | +| **测试总项数** | **248 项**(功能 54 + 性能 26 + API 69 + 静态 99+) | +| **综合通过率** | **78.2%** | +| **发现问题总数** | **36 个** | +| **CRITICAL** | **4 个** | +| **HIGH** | **8 个** | +| **MEDIUM** | **15 个** | +| **LOW** | **9 个** | + +## 3. 关键发现 + +### CRITICAL(阻塞 Beta 发布) + +| ID | 来源 | 问题 | 影响 | +|----|------|------|------| +| C-01 | 小程序 | `inject_auth` 写明文键,`request.ts` 只读加密键,所有 API 无 token | 小程序所有认证功能不可用 | +| C-02 | 小程序 | `secure-storage.ts` UTF-16 截断中文,加密存储后解密损坏 | 用户数据(含中文名)存储失败 | +| C-03 | Web 兼容 | 移动端 375px 表格不可用,无响应式替代布局 | 移动端用户完全无法操作 | +| C-04 | Web 兼容 | 移动横屏 812x375 内容区域空白 | 横屏模式页面无法使用 | + +### HIGH(影响核心业务流程) + +| ID | 来源 | 问题 | 影响 | +|----|------|------|------| +| H-01 | Web 功能 | 患者创建表单缺少前端必填校验,空表单提交成功 | 脏数据进入系统 | +| H-02 | Web 功能 | 预约列表 API 网络连接异常,无数据显示 | 预约管理不可用 | +| H-03 | Web 兼容 | 平板 768px 表格数据不加载 | 平板端不可用 | +| H-04 | Web 性能 | 患者列表 LCP 2643ms(render delay 99.8%) | 页面加载慢 | +| H-05 | Web 性能 | 仪表盘 API 每个端点重复调用 4 次 | 不必要的网络/服务器负载 | +| H-06 | API | 健康数据 DTO-Entity 映射断裂,测量值全存 null(通过率 20%) | 日常监测功能实质失效 | +| H-07 | API | 500 字符文章标题导致 HTTP 500 内部错误 | 应返回 400 验证错误 | +| H-08 | 静态分析 | Web 前端 10+ 处 `.catch(() => {})` 静默吞错 | 错误不可追踪 | + +## 4. 各维度通过率 + +| 测试域 | 通过率 | 评级 | +|--------|--------|------| +| API 端点(69 项) | 82.6% | B | +| 小程序 UI 渲染(38 项) | 100% | A | +| 小程序功能(应用内 3 项) | 0% | F(token 问题) | +| 小程序功能(API 直测 4 项) | 100% | A | +| Web 前端功能(8 大领域) | 62.5%(5/8 完全通过) | B- | +| Lighthouse Desktop | 94/100/100 | A | +| Lighthouse Mobile | 94/100/100 | A | +| Web Desktop 视口 | PASS | A | +| Web Tablet 视口 | FAIL | D | +| Web Mobile 视口 | FAIL | F | + +## 5. 发布就绪度判定 + +### 结论: **CONDITIONAL BETA** — 需修复 4 个 CRITICAL + 3 个 HIGH 后可发布 + +### 阻塞项(必须修复,预计 3-4 天) + +1. **C-01/C-02 小程序 token/加密问题** — 统一 `safeGet` fallback + 修复 UTF-8 编码(预计 3h) +2. **C-03/C-04 移动端响应式** — 添加卡片视图 + 修复 768px 断点(预计 2d) +3. **H-01 患者表单验证** — 前端添加 `form.validateFields()`(预计 1h) +4. **H-06 健康数据 DTO 映射** — 修复字段映射(预计 4h) +5. **H-07 文章标题 500 错误** — 添加 DTO 长度校验(预计 30min) + +### 建议项(Beta 后迭代,预计 5-7 天) + +- M-01~M-05: 对比度/暗色模式/API 校验/XSS/搜索等 +- L-01~L-09: 弃用警告/i18n/内联样式等 + +## 6. 报告索引 + +| 章节 | 文件 | +|------|------| +| 执行摘要(本文档) | `01-executive-summary.md` | +| Web 前端功能测试 | `02-web-functional.md` | +| Web 性能与兼容性测试 | `03-web-perf-compat.md` | +| 小程序功能测试 | `04-miniprogram.md` | +| API 深度测试 | `05-api-deep-test.md` | +| 静态代码分析 | `06-static-analysis.md` | +| 跨部门头脑风暴 | `07-brainstorm.md` | +| Beta 就绪验收清单 | `08-beta-checklist.md` | diff --git a/docs/audits/v3-beta/02-web-functional.md b/docs/audits/v3-beta/02-web-functional.md new file mode 100644 index 0000000..4b2f963 --- /dev/null +++ b/docs/audits/v3-beta/02-web-functional.md @@ -0,0 +1,119 @@ +# Web 前端核心业务功能测试 + +> 测试工具: chrome-devtools MCP | 环境: Chrome, 1920x1080 +> 测试账号: admin / Admin@2026 | 截图: `docs/qa/screenshots/` + +## 1. 登录流程 — PASS + +| 测试项 | 结果 | 说明 | +|--------|------|------| +| 登录页渲染 | PASS | 双栏布局,品牌信息完整 | +| 登录后跳转 | PASS | 跳转至工作台 `/#/` | +| 侧边栏菜单 | PASS | 7 个一级菜单加载(工作台/患者中心/随访关怀/健康监测/运营管理/AI助手/系统管理) | +| 用户信息显示 | PASS | 右上角"系统管理员" + 头像 | +| 权限不足页面 | PASS | 403 页面清晰,含返回首页按钮 | +| XSS 安全 | PASS | SQL 注入测试数据 `Robert"); DROP TABLE patients;--` 正确转义显示 | + +## 2. 患者管理 — FAIL (2 issues) + +| 测试项 | 结果 | 说明 | +|--------|------|------| +| 患者列表加载 | PASS | 136 条记录,7 页分页 | +| 分页切换 | PASS | 第 2 页数据正确 | +| 创建表单打开 | PASS | 4 个分组(基本信息/联系方式/医疗信息/紧急联系人) | +| 编辑表单 | PASS | 预填充已有数据 | +| **空表单提交** | **FAIL** | 空表单成功提交创建患者(后端有校验但前端未拦截) | +| **搜索功能** | **FAIL** | 输入 "Test" 搜索后列表仍显示全部 136 条 | + +### H-01: 患者创建表单缺少前端必填校验 + +- **严重性:** HIGH +- **证据:** 点击"保存"空表单后审计日志显示"创建 了 患者" +- **根因:** Ant Design Form 未配置 `rules: [{ required: true }]` 或未调用 `form.validateFields()` +- **修复:** 在 `PatientList.tsx` 的 DrawerForm 中添加 `rules` 配置,提交前调 `form.validateFields()` +- **预计工时:** 1h + +### M-01: 患者搜索不生效 + +- **严重性:** MEDIUM +- **证据:** 搜索框输入 "Test" + 回车,列表无变化 +- **根因:** 搜索框 `keyword` 参数可能未正确传递到 API 请求 +- **修复:** 检查搜索输入与 API 参数绑定 +- **预计工时:** 2h + +## 3. 健康数据/实时监控 — PASS + +| 测试项 | 结果 | 说明 | +|--------|------|------| +| 实时监控页 | PASS | 危急/高危/中等/低危告警计数正确 | +| 告警面板 | PASS | 1 个高危患者活跃告警 | +| 告警列表 | PASS | 5 条告警记录,状态/严重程度正确 | +| 筛选功能 | PASS | 患者下拉框存在 | + +## 4. 预约管理 — FAIL (1 issue) + +| 测试项 | 结果 | 说明 | +|--------|------|------| +| 预约列表页渲染 | PASS | 表头正确(患者/医护/类型/日期/时段/状态/创建时间/备注/操作) | +| **预约数据** | **FAIL** | 表格显示 "No data" + "网络连接异常,请检查网络" | +| 新建预约按钮 | PASS | 按钮可见 | + +### H-02: 预约列表 API 网络连接异常 + +- **严重性:** HIGH +- **证据:** 页面显示"网络连接异常"No data"同时出现 +- **根因:** 可能是后端 API 错误或前端 API 路径不匹配 +- **修复:** 检查 `/api/v1/health/appointments` 端点状态和前端 API 路径 +- **预计工时:** 2h + +## 5. 咨询管理 — PASS + +| 测试项 | 结果 | 说明 | +|--------|------|------| +| 咨询列表加载 | PASS | 18 条咨询记录 | +| 状态显示 | PASS | 已关闭/进行中/等待中正确 | +| 操作按钮 | PASS | 进行中的会话显示"关闭"按钮 | +| 未读消息计数 | PASS | 患者端/医护端分别显示 | +| 筛选/导出 | PASS | 状态筛选、日期范围、导出按钮均存在 | + +## 6. 工作台/仪表盘 — PASS_WITH_ISSUES + +| 测试项 | 结果 | 说明 | +|--------|------|------| +| 工作台首页 | PASS | 6 大状态卡片 + 统计 + 模块状态 + 活跃度 | +| 系统状态 | PASS | PostgreSQL/API/定时任务/文件存储/消息队列/缓存 全绿 | +| 统计数据 | PASS | 注册用户 27/今日活跃 4/本周 9/月活 18 | +| 最近操作 | PASS | 实时显示登录/创建/删除操作 | +| 通知面板 | PASS | 危急值告警和待办事项正常 | +| 侧边栏折叠 | PASS | 折叠后仅图标,悬停展开子菜单 | +| **Admin Dashboard** | **FAIL** | `/#/health/admin-dashboard` 显示 403 | + +### M-02: Admin Dashboard URL 直接访问 403 + +- **严重性:** MEDIUM +- **说明:** AdminDashboard 组件存在但路由未注册,该页面可能仅作为工作台内嵌组件使用 +- **修复:** 移除直接访问路径或正确注册路由并配置权限 +- **预计工时:** 1h + +## 7. 主题切换 — PASS (4/4) + +| 主题 | 结果 | 说明 | +|------|------|------| +| 信任蓝(默认) | PASS | 蓝色系侧边栏 | +| 深邃夜色 | PASS | 深色侧边栏和页头 | +| 翡翠清雅 | PASS | 绿色系 | +| 温润东方 | PASS | 暖色调 | +| 持久化 | PASS | localStorage `hms-theme` 保存,刷新后保持 | + +## 8. 控制台警告 + +| 类型 | 消息 | 严重性 | +|------|------|--------| +| WARN | `[antd: Drawer] width is deprecated. Please use size instead.` | LOW | +| WARN | `[antd: List] component is deprecated. And will be removed in next major version.` | LOW | + +## 小结 + +- **完全通过领域:** 5/8(登录/健康数据/咨询/工作台/主题) +- **存在问题领域:** 3/8(患者管理/预约/仪表盘路由) +- **HIGH 问题:** 2 个 | **MEDIUM 问题:** 2 个 | **LOW 问题:** 2 个 diff --git a/docs/audits/v3-beta/03-web-perf-compat.md b/docs/audits/v3-beta/03-web-perf-compat.md new file mode 100644 index 0000000..5a5891c --- /dev/null +++ b/docs/audits/v3-beta/03-web-perf-compat.md @@ -0,0 +1,175 @@ +# Web 前端性能与兼容性测试 + +> 测试工具: chrome-devtools MCP (Lighthouse + Performance Trace + Emulate) +> 截图: `g:\hms\screenshots/` | 追踪: `g:\hms\trace-*.json` + +## 1. Lighthouse 审计 + +### 1.1 Desktop (Navigation) + +| 类别 | 分数 | 状态 | +|------|------|------| +| Accessibility | **94** | GOOD | +| Best Practices | **100** | PERFECT | +| SEO | **100** | PERFECT | +| Agentic Browsing | **61** | NEEDS_WORK | + +**失败审计项 (4):** +1. CLS 0.127 超过 0.1 阈值(Desktop 有,Mobile 无) +2. 浅色模式 `#94a3b8` 灰色文字在白底上对比度 2.56:1(需 4.5:1) +3. h1 后直接跳 h3,缺少 h2 层级 +4. llms.txt 文件缺少 H1 标题和链接 + +### 1.2 Mobile (Navigation) + +| 类别 | 分数 | 状态 | +|------|------|------| +| Accessibility | **94** | GOOD | +| Best Practices | **100** | PERFECT | +| SEO | **100** | PERFECT | +| Agentic Browsing | **67** | NEEDS_WORK | + +**失败项与 Desktop 相同**(color-contrast + heading-order + llms-txt)。Mobile CLS 为 0 通过。 + +### 1.3 Dark Mode (Snapshot) + +| 类别 | 分数 | 下降 | +|------|------|------| +| Accessibility | **92** | -2 | +| Best Practices | **100** | — | +| SEO | **80** | -20 | + +**Dark Mode 额外问题:** +- 侧边栏菜单项对比度不足(4.39:1 / 3.95:1 / 4.45:1,均未达 4.5:1) +- 表单元素缺少 `label` 关联 +- 分页链接不可爬取 + +## 2. Core Web Vitals + +### 2.1 工作台(Dashboard) + +| 指标 | 值 | 评级 | +|------|-----|------| +| **LCP** | **1381ms** | NEEDS IMPROVEMENT | +| **CLS** | **0.04** | GOOD | +| **TTFB** | **6ms** | GOOD | +| DOM 大小 | 311 elements | GOOD | +| DOM 深度 | 13 层 | GOOD | + +**LCP 瓶颈:** TTFB 6ms (0.4%) + Render Delay **1375ms (99.6%)** +**CLS 根因:** Noto Sans SC 字体从 Google Fonts 加载导致 FOUT,5 个 woff2 文件 + +### 2.2 患者列表 + +| 指标 | 值 | 评级 | +|------|-----|------| +| **LCP** | **2643ms** | NEEDS IMPROVEMENT | +| **CLS** | **0.01** | GOOD | +| **TTFB** | **4ms** | GOOD | +| DOM 大小 | 944 elements | MODERATE | + +**LCP 瓶颈:** TTFB 4ms (0.2%) + Render Delay **2639ms (99.8%)** + +**强制回流:** 总计 **460ms** +- `measureScrollbarSize` (antd): 341ms + 43ms +- `setScaleParam` (antd): 76ms +- 全部来自 Ant Design 表格组件内部 + +## 3. 多视口兼容性 + +### 3.1 Desktop 1920×1080 — PASS +- 侧边栏展开,菜单完整 +- 表格完整显示 +- **注意:** 仪表盘出现"网络连接异常"错误提示 + +### 3.2 Laptop 1366×768 — PASS +- 侧边栏正常展开 +- 患者表格完整,分页器可见 +- 筛选栏全部可见 + +### 3.3 Tablet iPad 768×1024 — **FAIL (HIGH)** + +- 侧边栏折叠为仅图标模式 +- **面包屑显示"页面"而非实际名称** +- **表格数据完全未加载** — 主内容区只有头部和筛选栏,表格区域为空 +- 评级: **H-03** + +### 3.4 Mobile iPhone 375×812 — **FAIL (CRITICAL)** + +- 侧边栏展开覆盖全屏 +- 8 列数据在 375px 宽度严重挤压 +- 出现 3 条错误消息("网络连接异常" + 2×"加载数据失败") +- 操作按钮(edit/delete)极小,触摸目标不足 44px +- 评级: **C-03** — 应提供卡片视图替代 + +### 3.5 Mobile Landscape 812×375 — **FAIL (CRITICAL)** + +- **内容区域完全空白** — main 区域只有 loading/busy 状态 +- 面包屑显示"页面" +- 评级: **C-04** + +## 4. Dark Mode 对比度问题 + +### 4.1 侧边栏低对比度 + +| 元素 | 对比度 | 标准 | +|------|--------|------| +| 跳转链接 / H logo | 4.07:1 | 需 4.5:1 | +| 患者中心 | 4.39:1 | 需 4.5:1 | +| 患者管理 | 3.95:1 | 需 4.5:1 | + +### 4.2 系统管理卡片浅色背景(Dark Mode 下不协调) + +| 元素 | 对比度 | 背景 | +|------|--------|------| +| 运行中 | 3.15:1 | 浅绿 | +| 菜单管理 | 3.84:1 | 浅蓝 | +| 系统配置 | 3.07:1 | 浅黄 | + +**根因:** 系统管理区块在 Dark Mode 下仍使用浅色背景,未跟随主题切换。 + +## 5. 网络请求分析 + +### 5.1 API 重复调用 + +仪表盘每个端点被调用 **4 次**: + +| 端点 | 调用次数 | +|------|---------| +| `/health/admin/statistics/patients` | ×4 | +| `/health/admin/statistics/consultations` | ×4 | +| `/health/admin/statistics/follow-ups` | ×4 | +| `/health/admin/points/statistics` | ×4 | +| `/health/admin/statistics/health-data` | ×4 | +| `/health/admin/statistics/dialysis` | ×4 | +| `/health/doctors` | ×4 | +| `/menus/user` | ×4 | +| `/config/themes` | ×4 | +| `/health/action-inbox` | ×4 | + +**根因:** 可能来自 React Strict Mode 双重渲染 + 组件重复挂载 +**评级:** H-05 + +### 5.2 第三方资源 + +| 资源 | 大小 | 影响 | +|------|------|------| +| Google Fonts (Noto Sans SC) | 1.3 MB | 最大外部资源,导致 CLS | + +## 6. 问题汇总 + +| ID | 严重性 | 问题 | 修复建议 | 工时 | +|----|--------|------|----------|------| +| C-03 | CRITICAL | Mobile 375px 表格不可用 | 添加 `<768px` 卡片视图 | 2d | +| C-04 | CRITICAL | Mobile 横屏内容空白 | 修复 812×375 路由加载 | 4h | +| H-03 | HIGH | Tablet 768px 数据不加载 | 修复断点 + 侧边栏同步 | 4h | +| H-04 | HIGH | 患者列表 LCP 2643ms | 字体预加载 + 虚拟滚动 | 1d | +| H-05 | HIGH | 仪表盘 API ×4 重复调用 | 检查 useEffect 依赖 | 4h | +| M-03 | MEDIUM | 浅色模式 #94a3b8 对比度 | 改为 #64748b | 30min | +| M-04 | MEDIUM | Dark Mode 系统管理卡片 | 深色背景变体 | 4h | +| M-05 | MEDIUM | Antd 表格 reflow 460ms | 固定 scroll.x/y | 2h | +| M-06 | MEDIUM | Noto Sans SC 1.3MB CLS | font-display: optional | 1h | +| M-07 | MEDIUM | 面包屑显示"页面" | 修复 tablet/mobile 路由名 | 1h | +| L-01 | LOW | heading-order h1→h3 | 插入 h2 或 aria-level | 30min | +| L-02 | LOW | 表单元素缺 label | 添加 aria-label | 1h | +| L-03 | LOW | antd Drawer width 弃用 | 迁移到 size 属性 | 30min | diff --git a/docs/audits/v3-beta/04-miniprogram.md b/docs/audits/v3-beta/04-miniprogram.md new file mode 100644 index 0000000..acfbfeb --- /dev/null +++ b/docs/audits/v3-beta/04-miniprogram.md @@ -0,0 +1,146 @@ +# 小程序功能测试报告 + +> 测试工具: weapp-local MCP | 环境: 微信开发者工具, iPhone 12/13 Pro 模拟器 +> iOS 10.0.1, 390×844 | 分支: feat/media-library-banner + +## 1. 连接与认证 + +| 项目 | 结果 | 说明 | +|------|------|------| +| MCP 连接 | PASS | ws://localhost:9420 连接成功 | +| inject_auth | PASS_WITH_ISSUES | 报告"注入成功"但存在集成问题(C-01) | +| Auth 手动恢复 | PASS | 通过 `__hms` bridge 手动 restoreAuth 成功 | + +## 2. Tab 页面测试 + +### 2.1 首页 (pages/index/index) — PASS + +| 检查项 | 结果 | 详情 | +|--------|------|------| +| 问候语 | PASS | "晚上好,系统管理员" + "5月21日周四" | +| 消息铃铛 | PASS | 可点击 | +| 签到卡片 | PASS | 进度环 0%,4 个 capsule(血压/心率/血糖/体重) | +| 今日体征 | PASS | 4 张卡片,值"---",标签"未记录" | +| 操作按钮 | PASS | "记录体征" + "预约挂号" | +| SOS 按钮 | PASS | 存在 | +| 访客模式 | PASS | 未登录显示轮播图 + 健康资讯 + 注册 CTA | +| Console 错误 | PASS | 无 | + +### 2.2 健康 Tab (pages/health/index) — PASS_WITH_ISSUES + +| 检查项 | 结果 | 详情 | +|--------|------|------| +| 页面加载 | PASS | 分段选项卡(血压/心率/血糖/体重) | +| 录入表单 | PASS | 收缩压+舒张压输入框 + 参考范围提示 | +| 趋势图 | PASS | 空状态"暂无趋势数据"正确显示 | +| **保存功能** | **FAIL** | 日志 `[health] 保存体征数据失败: {}`(C-01) | + +### 2.3 助手 Tab / AI 聊天 (pages/messages/index) — PASS + +| 检查项 | 结果 | 详情 | +|--------|------|------| +| 页面加载 | PASS | 标题"健康助手 . 小华" | +| 在线状态 | PASS | 绿色圆点 + "24小时在线" | +| 输入框 | PASS | placeholder "输入您的问题..." | +| 发送按钮 | PASS | 存在,无输入时 disabled | + +### 2.4 我的 Tab (pages/profile/index) — PASS + +| 检查项 | 结果 | 详情 | +|--------|------|------| +| 用户卡片 | PASS | 头像"系" + "系统管理员" | +| 统计数据 | PASS | 健康积分 0 + 连续打卡 0 天 | +| 功能菜单 | PASS | 5 大分组 17 个菜单项完整 | +| 退出登录 | PASS | 红色按钮存在 | +| Console 错误 | PASS | 无 | + +### 2.5 商城 Tab — 不在 TabBar 内,需导航访问 + +## 3. 非 Tab 页面测试 + +### 3.1 积分商城 (pages/mall/index) — PASS_WITH_ISSUES + +| 检查项 | 结果 | 详情 | +|--------|------|------| +| 页面加载 | PASS | 积分头部 + 签到按钮 | +| 空状态 | PASS | "暂无商品" + "更多好物即将上架" | +| **签到功能** | **FAIL** | 日志 `[points] 签到失败: {}`(C-01) | + +### 3.2 咨询列表 (pages/consultation/index) — PASS_WITH_ISSUES + +| 检查项 | 结果 | 详情 | +|--------|------|------| +| 页面导航 | PASS | 成功导航 | +| 骨架屏 | PASS | 4 个 loading card | +| **数据加载** | **FAIL** | 永久 loading 状态,无超时提示(C-01 + BUG-03) | + +## 4. 核心功能 API 验证(绕过小程序 request 层) + +| API | 方法 | 结果 | 详情 | +|-----|------|------|------| +| 积分账户 | GET /health/points/account | **PASS** | 余额 40,总获得 50,总消费 10 | +| 血压保存 | POST /health/patients/{id}/vital-signs | **PASS** | 200,返回完整记录 | +| 每日签到 | POST /health/points/checkin | **PASS** | 200,checked_in_today=true,连续 2 天 | +| 咨询列表 | GET /health/consultation-sessions | **PASS** | 200,1 条 active 会话 | + +**结论:** 后端 API 全部正常,所有功能性问题源于小程序端 token 读取。 + +## 5. BUG 详细分析 + +### C-01: inject_auth 与 request.ts 的 storage 键不匹配 + +- **严重性:** CRITICAL +- **文件:** `services/request.ts:23-29` +- **现象:** `inject_auth` 写入明文键(`access_token`),`request.ts` 的 `safeGet()` 只调用 `secureGet()`(读 `_es_` 前缀加密键),不 fallback 到明文键 +- **根因:** `safeGet` 在 `secureGet` 返回空字符串时不 fallback(空字符串不抛异常,只在 catch 中 fallback)。而 `auth.ts` 的 `storageGet` 在 `secureGet` 返回 falsy 时正确 fallback +- **影响:** 所有需要认证的功能不可用(体征保存、签到、咨询、数据加载) +- **修复:** 统一 `safeGet` 和 `storageGet` 的 fallback 逻辑,或让 `inject_auth` 写入加密键 +- **预计工时:** 1h + +### C-02: secure-storage.ts UTF-16 截断中文字符 + +- **严重性:** CRITICAL +- **文件:** `utils/secure-storage.ts:13-23` +- **现象:** `toBase64` 使用 `Uint8Array` 截断 UTF-16 高位字节 +- **根因:** `charCodeAt` 返回的 UTF-16 编码值超过 255 时被截断为 8 位 +- **影响:** 任何含中文的数据(如 `display_name`="系统管理员")经 encrypt-decrypt 循环后损坏,`JSON.parse` 失败 +- **修复:** 使用 `TextEncoder`/`TextDecoder` 进行 UTF-8 编解码 +- **预计工时:** 2h + +### BUG-03: 咨询列表无超时处理 + +- **严重性:** MEDIUM +- **文件:** `pages/consultation/index` +- **现象:** API 失败时无用户反馈,页面永远显示骨架屏 +- **修复:** 添加加载超时和错误状态 UI +- **预计工时:** 1h + +### BUG-04: 错误日志输出空对象 + +- **严重性:** MEDIUM +- **现象:** 签到/体征保存失败时 `catch` 输出 `{}` +- **修复:** 使用 `JSON.stringify(err, Object.getOwnPropertyNames(err))` 输出完整错误 +- **预计工时:** 30min + +## 6. 测试统计 + +| 类别 | 测试项 | PASS | FAIL | PASS_WITH_ISSUES | +|------|--------|------|------|------------------| +| 连接与认证 | 3 | 1 | 0 | 2 | +| Tab 页面 | 4 | 3 | 0 | 1 | +| 非 Tab 页面 | 2 | 0 | 0 | 2 | +| UI 元素 | 38 | 38 | 0 | 0 | +| 核心功能(API 直测) | 4 | 4 | 0 | 0 | +| 核心功能(应用内) | 3 | 0 | 3 | 0 | +| **合计** | **54** | **46** | **3** | **5** | + +**UI 渲染通过率:** 100% (38/38) +**API 直测通过率:** 100% (4/4) +**应用内功能通过率:** 0% (0/3) — 全部因 C-01 失败 +**综合通过率:** 85.2% (46/54) + +## 7. 评价 + +**UI 层质量:** 优秀(A 级)— 所有页面正确渲染,空状态处理完善,设计系统一致性好。 + +**功能层质量:** 失败(F 级)— 但根因集中在一个 CRITICAL 问题(C-01 token 读取),修复后预计 100% 通过。后端 API 经独立验证全部正常。 diff --git a/docs/audits/v3-beta/05-api-deep-test.md b/docs/audits/v3-beta/05-api-deep-test.md new file mode 100644 index 0000000..08f3d50 --- /dev/null +++ b/docs/audits/v3-beta/05-api-deep-test.md @@ -0,0 +1,159 @@ +# API 端点深度测试报告 + +> 测试工具: curl/Bash | 环境: http://localhost:3000 +> 测试账号: admin / Admin@2026 (完整权限) | 总用例: 69 + +## 1. 模块通过率汇总 + +| 模块 | 测试数 | 通过 | 失败 | 通过率 | +|------|--------|------|------|--------| +| 认证与权限 | 8 | 8 | 0 | **100%** | +| 患者 CRUD | 11 | 10 | 1 | **90.9%** | +| 患者分页/注入 | 7 | 5 | 2 | **71.4%** | +| 患者删除 | 2 | 2 | 0 | **100%** | +| 健康数据 | 5 | 1 | 4 | **20%** | +| 预约系统 | 7 | 7 | 0 | **100%** | +| 咨询管理 | 9 | 7 | 2 | **77.8%** | +| 内容管理 | 13 | 10 | 3 | **76.9%** | +| 通用/跨切面 | 7 | 7 | 0 | **100%** | +| **总计** | **69** | **57** | **12** | **82.6%** | + +## 2. 认证与权限 — 100% PASS + +| ID | 测试 | 结果 | +|----|------|------| +| AUTH-01 | 错误密码 | PASS — `message=未授权` | +| AUTH-02 | 不存在的用户 | PASS — `message=未授权` | +| AUTH-03 | 无 Token 访问 | PASS — HTTP 401 | +| AUTH-04 | 无效 Token | PASS — HTTP 401 | +| AUTH-05 | 空 body 登录 | PASS — 429 限流触发 | +| AUTH-06 | SQL 注入 (`' OR 1=1 --`) | PASS — 无数据泄漏 | +| AUTH-07 | 超长密码 (10000 字符) | PASS — 429 限流触发 | +| AUTH-08 | 有效 Token | PASS — 200 + data | + +**亮点:** 限流机制有效,登录端点不泄漏信息(统一返回"未授权"),SQL 注入被正确处理。 + +## 3. 患者 CRUD — 90.9% PASS + +| ID | 测试 | 结果 | 说明 | +|----|------|------|------| +| PATIENT-01 | 空名称创建 | PASS | `400: 患者姓名不能为空` | +| PATIENT-02 | 500 字符名称 | PASS | `400: 长度不能超过255` | +| PATIENT-03 | 未来出生日期 (2099) | PASS | `400: 出生日期不能是未来日期` | +| PATIENT-04 | XSS in name (`` 直接存入 name 字段 +- 前端 React 默认转义,但建议服务端也做消毒 +- **修复:** 添加 HTML sanitize 或正则剥离标签 + +### 患者分页/注入测试 + +| ID | 测试 | 结果 | +|----|------|------| +| PATIENT-10 | limit=10000 | **FAIL (LOW)** — 无上限,可能导致性能问题 | +| PATIENT-12 | SQL 注入 in search | **FAIL (MEDIUM)** — 连接错误 (HTTP 000) | + +## 4. 健康数据 — 20% PASS (最差模块) + +| ID | 测试 | 结果 | 说明 | +|----|------|------|------| +| HEALTH-01 | 极端血压 (0/0) | **FAIL** | HTTP 200,值存为 null | +| HEALTH-02 | 极端心率 (999) | **FAIL** | HTTP 200,值存为 null | +| HEALTH-03 | 负值 (-10) | **FAIL** | HTTP 200,值存为 null | +| HEALTH-04 | 无效 UUID | PASS | `422: UUID parsing failed` | +| HEALTH-05 | 未来日期 (2099) | **FAIL** | HTTP 200,记录被创建 | + +### H-06: 日常监测 DTO-Entity 映射断裂 (HIGH) + +**这是本次测试发现的最严重的后端问题。** + +- **现象:** API 接受 `indicator_type`、`value`、`systolic`、`diastolic` 等字段但静默忽略,创建的记录所有测量字段为 null +- **根因:** DTO 字段与 Entity 列名不匹配。DTO 使用 `systolic`/`diastolic`,Entity 期望 `morning_bp_systolic`/`morning_bp_diastolic` +- **影响:** 日常监测功能实质失效 — 小程序录入的体征数据无法正确存储 +- **修复:** 重构 DTO 字段映射,或统一 DTO/Entity 字段命名 +- **预计工时:** 4h + +**同时发现:** 无值范围校验(血压 0、心率 999 被接受)、未来 record_date 无校验。 + +## 5. 预约系统 — 100% PASS + +| ID | 测试 | 结果 | +|----|------|------| +| APPOINT-01 | 列表查询 | PASS | +| APPOINT-02 | 空 doctor_id | PASS — 422 | +| APPOINT-03 | 无效 UUID | PASS — 422 | +| APPOINT-04 | 不存在的预约 | PASS — 404 | +| APPOINT-05 | page=0 | PASS | +| APPOINT-11 | 排班已满 | PASS — `400: 排班已满` | +| APPOINT-12 | 重复预约 | PASS — `400: 排班已满` | + +**亮点:** UUID 校验、容量检查、404 处理全部正确。 + +## 6. 咨询管理 — 77.8% PASS + +| ID | 测试 | 结果 | +|----|------|------| +| CONSULT-02 | 空描述创建 | **FAIL (LOW)** — 接受空描述 | +| CONSULT-05 | XSS in description | **FAIL (MEDIUM)** — XSS 存储原值 | +| CONSULT-06~09 | 评分范围 1-5 | **PASS** — 校验完善 | + +**亮点:** 评分校验优秀(1-5 范围 + 只能评已关闭会话)。 + +## 7. 内容管理 — 76.9% PASS + +| ID | 测试 | 结果 | +|----|------|------| +| ARTICLE-04 | 500 字符标题 | **FAIL (HIGH)** — HTTP 500 内部错误 | +| CATEGORY-02 | 空分类名称 | **FAIL (MEDIUM)** — 接受空名称 | +| TAG-04 | 重复标签名 | **FAIL (LOW)** — 允许重复 | + +### ARTICLE-04: 500 字符标题导致 500 错误 (HIGH) + +- **现象:** 500 字符文章标题返回 HTTP 500 Internal Server Error +- **根因:** DTO 缺少 `#[validate(length(max=255))]`,数据库列长度约束违反导致未处理的 DB 错误 +- **修复:** 添加 DTO 长度校验 + 全局 DB 错误映射 +- **预计工时:** 30min + +### CATEGORY-02: 空分类名称被接受 (MEDIUM) + +- 文章标题有空校验,标签名称有空校验,但分类名称没有 +- **修复:** 添加 `#[validate(length(min=1))]` + +## 8. 通用/跨切面 — 100% PASS + +| ID | 测试 | 结果 | +|----|------|------| +| GENERIC-01 | 3 个并发更新 | PASS — 1 成功 + 2 冲突 (409) | +| GENERIC-02 | 错误 JSON body | PASS — 400 | +| GENERIC-03 | 缺少 Content-Type | PASS — 415 | +| GENERIC-04 | GET 带 body | PASS — body 被忽略 | +| GENERIC-05 | 超大页码 | PASS — 空列表 | +| GENERIC-06 | 快速连续请求 | PASS — 全 200 | +| GENERIC-07 | 不存在的文章 ID | PASS — 404 | + +**亮点:** 乐观锁在并发下表现完美(1 成功 + 2 冲突),HTTP 状态码使用规范。 + +## 9. 失败项汇总 + +| ID | 严重性 | 模块 | 问题 | 修复 | 工时 | +|----|--------|------|------|------|------| +| H-06 | HIGH | 健康数据 | DTO-Entity 映射断裂 | 重构字段映射 | 4h | +| H-07 | HIGH | 内容管理 | 500 字符标题 → HTTP 500 | 添加 DTO 校验 | 30min | +| M-08 | MEDIUM | 健康数据 | 极端值无校验 | 添加范围校验 | 2h | +| M-09 | MEDIUM | 健康数据 | 未来 record_date | 添加日期校验 | 30min | +| M-10 | MEDIUM | 咨询 | XSS 存储未消毒 | HTML sanitize | 1h | +| M-11 | MEDIUM | 内容管理 | 空分类名被接受 | 添加 validate | 30min | +| M-12 | MEDIUM | 患者 | SQL 注入导致连接错误 | 调查 URL 编码 | 2h | +| M-13 | MEDIUM | 患者 | XSS 存储未消毒 | HTML sanitize | 1h | +| L-04 | LOW | 患者 | limit 无上限 | 设 max=200 | 30min | +| L-05 | LOW | 咨询 | 空描述被接受 | validate 或文档 | 30min | +| L-06 | LOW | 内容管理 | 重复标签名 | 唯一约束 | 1h | diff --git a/docs/audits/v3-beta/06-static-analysis.md b/docs/audits/v3-beta/06-static-analysis.md new file mode 100644 index 0000000..0fd0090 --- /dev/null +++ b/docs/audits/v3-beta/06-static-analysis.md @@ -0,0 +1,139 @@ +# 前端代码静态分析报告 + +> 分析范围: apps/web/src/ (316 TS/TSX) + apps/miniprogram/src/ (167 TS/TSX) +> 分析工具: Grep/Read/Bash + +## 1. TypeScript 类型安全 — MEDIUM + +### Web 前端 + +生产代码仅 1 处 `any`: + +| 文件 | 行号 | 问题 | +|------|------|------| +| `hooks/usePaginatedData.ts` | 39 | `fetchFn: (...args: any[]) =>` — 建议用泛型 `A extends unknown[]` | + +测试文件中 17 处 `as any`(mock 场景),影响低。 + +### 小程序 — 10 处 `as any` + +| 文件 | 行号 | 问题 | 严重性 | +|------|------|------|--------| +| `app.tsx` | 24, 29 | `(globalThis as any).__hms` | LOW — 调试辅助 | +| `pages/login/index.tsx` | 9 | `(__wxConfig as any).envVersion` | MEDIUM | +| `services/request.ts` | 250 | `method: method as any` | MEDIUM | +| `pages/pkg-health/device-sync/index.tsx` | 69 | `(bleManager as any).dataBuffer` | HIGH | +| `pages/appointment/create/index.tsx` | 132 | `(Taro.requestSubscribeMessage as any)` | MEDIUM | + +**修复建议:** 创建 `types/global.d.ts` 和 `types/taro.d.ts` 补全缺失类型。 + +## 2. 错误处理 — HIGH + +### Web 前端静默吞错 (10+ 处) + +| 文件 | 行号 | 模式 | +|------|------|------| +| `pages/Home.tsx` | 224, 232, 238 | 个人统计加载失败被吞 | +| `pages/Roles.tsx` | 46 | 权限列表加载失败被吞 | +| `pages/health/ArticleManageList.tsx` | 119 | 文章列表加载失败被吞 | +| `pages/health/DialysisManageList.tsx` | 49 | 透析列表加载失败被吞 | +| `pages/health/components/DoctorSelect.tsx` | 28 | 医生列表加载失败被吞 | +| `pages/health/components/workbench/OperatorWorkbench.tsx` | 35 | 工作台数据加载失败被吞 | + +另有 10 处 `catch { }`(ChatPage 4 处 / useAlertSSE 2 处 / MainLayout 1 处 / usePaginatedData 1 处 / NotificationPanel 1 处 / App.tsx 1 处)。 + +**修复:** `.catch(() => {})` → `.catch((err) => console.warn('[context] 操作失败:', err))`,或设置错误状态。 + +### 小程序 + +仅 1 处静默 catch(`followups/detail/index.tsx:58`),有注释解释,属合理模式。 + +## 3. 安全问题 — HIGH (1 处) + +### dangerouslySetInnerHTML 无消毒 + +`pages/health/articleEditor/ArticlePhonePreview.tsx:243`: +```tsx +
+``` + +- `content` 来自 wangEditor 富文本输出 +- 后台管理预览组件,内容由管理员创建(非 UGC) +- **仍建议引入 DOMPurify 做客户端消毒** +- 预计工时: 30min + +### 硬编码 URL — LOW + +| 文件 | 内容 | 评估 | +|------|------|------| +| `AiConfigPage.tsx:340,402` | `http://localhost:11434` | Ollama 默认 URL,仅作 placeholder | +| `miniprogram/services/request.ts:4` | `localhost:3000` fallback | 开发环境 fallback,生产需运行时校验 | + +**无硬编码密钥或密码。** ✅ + +## 4. 可访问性 — LOW + +- 未发现缺少 `alt` 的 `` — Web 前端全用 Ant Design 组件 +- 3 处 `onClick` 在非 button 元素上使用(MainLayout 侧边栏 logo/折叠按钮 + ActionThreadDrawer 事件链接) +- **修复:** 添加 `role="button"` + `tabIndex={0}` + `onKeyDown` + +## 5. 大文件 — MEDIUM + +### Web 前端 (500+ 行) + +| 文件 | 行数 | 建议 | +|------|------|------| +| `AdminDashboard.tsx` | 734 | 拆分统计卡片、图表、表格 | +| `ArticleManageList.tsx` | 654 | 拆分筛选栏、表格、详情抽屉 | +| `FollowUpTaskList.tsx` | 543 | 拆分筛选、列表、详情 | +| `ConsultationDetail.tsx` | 542 | 拆分消息区、信息栏 | +| `BannerManage.tsx` | 526 | 拆分表格和表单 | +| `AppointmentList.tsx` | 520 | 拆分筛选和表格 | +| `AiKnowledgePage.tsx` | 508 | 拆分列表和编辑 | + +所有文件在 800 行限制内(CLAUDE.md 规范),但建议拆分提升可维护性。 + +### 小程序 (300+ 行) + +| 文件 | 行数 | +|------|------| +| `daily-monitoring/index.tsx` | 449 | +| `health/index.tsx` | 376 | +| `index/index.tsx` | 371 | + +小程序文件总体控制得更好。 + +## 6. 国际化 — MEDIUM (不阻塞) + +- **Web 前端:** 97 个文件 / 375 处硬编码中文文本 +- **高频文件:** DashboardWidgets (47) / DoctorWorkbench (19) / OperatorWorkbench (18) +- **影响:** 当前定位国内单语平台,短期不影响 +- **建议:** 新代码使用 i18n key,旧代码逐步迁移 + +## 7. 内联样式 — LOW + +- **1,548 处** `style={{}}` 分布在 129 个文件 +- **高频:** DoctorWorkbench (68) / AdminDashboard (54) / OperatorWorkbench (49) / DashboardWidgets (47) +- 部分动态计算(width/height)不可避免,静态样式应迁移到 CSS + +## 8. 值得肯定的方面 + +1. **TypeScript 类型安全整体优秀** — 生产代码仅 1 处 `any` +2. **小程序已完全消除 Web API 依赖** — 无 `localStorage`/`btoa`/`atob` +3. **无硬编码密钥或密码** — 敏感值全走环境变量 +4. **eslint-disable 使用规范** — 每处有注释解释 +5. **所有文件在 800 行限制内** +6. **小程序 console 日志格式统一** — `[模块名] 描述: error` + +## 9. 问题汇总 + +| 严重性 | 问题 | 文件数 | 修复工作量 | +|--------|------|--------|-----------| +| HIGH | 静默吞错 `.catch(() => {})` | 10+ | 小 — 改为 warn 日志 | +| HIGH | dangerouslySetInnerHTML 无消毒 | 1 | 小 — 引入 DOMPurify | +| MEDIUM | 小程序 `as any` 类型断言 | 10 | 中 — 补全类型声明 | +| MEDIUM | 硬编码中文 (i18n) | 97 | 大 — 渐进迁移 | +| MEDIUM | 500+ 行大文件 | 7 | 中 — 拆分子组件 | +| LOW | 内联样式过多 | 129 | 大 — 渐进迁移 | +| LOW | localhost fallback URL | 2 | 小 — 运行时校验 | +| LOW | 非交互元素 onClick 缺 a11y | 3 | 小 | diff --git a/docs/audits/v3-beta/07-brainstorm.md b/docs/audits/v3-beta/07-brainstorm.md new file mode 100644 index 0000000..1c0f884 --- /dev/null +++ b/docs/audits/v3-beta/07-brainstorm.md @@ -0,0 +1,222 @@ +# 跨部门头脑风暴 — 问题研讨与优化方案 + +> 日期: 2026-05-21 | 参与方: 前端/后端/小程序/安全/UX/DevOps +> 基于 V3 Beta 综合测试发现 + +## 1. 会议议题 + +基于 5 个专家团队的测试发现,识别出 **4 个 CRITICAL + 8 个 HIGH + 15 个 MEDIUM** 问题。本次头脑风暴聚焦于: + +1. CRITICAL 问题修复方案与优先级 +2. 移动端响应式架构决策 +3. 小程序安全存储架构改进 +4. 后端 DTO-Entity 映射质量管控 +5. Beta 发布时间线 + +--- + +## 2. 议题一: 小程序认证链路断裂 (C-01 + C-02) + +### 问题 + +`inject_auth` → 明文键 → `request.ts safeGet` 只读加密键 → 所有 API 无 token +`secure-storage.ts` → UTF-16 截断 → 中文数据加密后解密损坏 + +### 方案讨论 + +| 方案 | 描述 | 优点 | 缺点 | +|------|------|------|------| +| **A. 统一 safeGet fallback** | `safeGet` 在 `secureGet` 返回空时 fallback 到明文键 | 改动最小(1 文件) | 认证路径依赖两套存储 | +| **B. inject_auth 写加密键** | MCP 注入时直接写 `_es_` 前缀加密键 | 根因修复 | MCP 需实现加密逻辑 | +| **C. 统一存储层重构** | 所有读写走单一 `storageGet/storageSet`,内部处理加密/明文 fallback | 架构最优 | 改动范围大 | + +### 决策 + +**采用方案 A + 修复 C-02**,预计 3h: +1. `request.ts safeGet` 添加与 `auth.ts storageGet` 一致的 fallback 逻辑 +2. `secure-storage.ts toBase64/fromBase64` 改用 `TextEncoder/TextDecoder` +3. 添加单元测试验证中文字符加密/解密循环 + +--- + +## 3. 议题二: 移动端响应式 (C-03 + C-04 + H-03) + +### 问题 + +- 375px: 表格不可用,列严重挤压 +- 812×375: 内容区域空白 +- 768px: 表格数据不加载 + +### 方案讨论 + +| 方案 | 描述 | 工时 | 效果 | +|------|------|------|------| +| **A. Ant Design ProTable 响应式** | 使用 `responsive` 配置自动切换卡片视图 | 2d | 列表页全覆盖 | +| **B. CSS Grid + 媒体查询** | 手写 `@media` 断点,表格→卡片 | 3d | 精细控制 | +| **C. 独立移动端组件** | 为移动端创建 `MobilePatientCard` 等组件 | 5d | 最佳 UX | + +### 决策 + +**采用方案 A**,Ant Design ProTable 自带 responsive 支持: +1. 为 `<768px` 启用 `cardView` 模式 +2. 修复 768px 断点侧边栏折叠同步问题 +3. 修复 812×375 高度不足导致懒加载未触发 + +**注意:** HMS 定位为 PC 管理后台,移动端支持优先级低于小程序。方案 A 满足"基本可用"即可。 + +--- + +## 4. 议题三: 健康数据 DTO 映射 (H-06) + +### 问题 + +日常监测 API 通过率 20%,DTO 字段(`systolic`/`diastolic`)与 Entity 列名(`morning_bp_systolic`/`morning_bp_diastolic`)不匹配,导致所有测量值存为 null。 + +### 根因分析 + +1. DTO 设计采用通用字段名,Entity 使用具体时段字段名 +2. Handler 层缺少 DTO→Entity 的显式映射逻辑 +3. SeaORM 隐式匹配字段名,不匹配的静默为 null + +### 修复方案 + +1. **DTO 重构:** 定义 `CreateDailyMonitoringReq` 明确映射到 Entity 字段 +2. **Handler 添加映射:** 显式 `entity.morning_bp_systolic = dto.systolic` 等 +3. **添加集成测试:** 确保写入后能正确读回 +4. **值范围校验:** 血压 60-300 / 心率 30-250 / 血糖 1-50 +5. **日期校验:** `record_date <= today` + +预计工时: 4h + +--- + +## 5. 议题四: 安全问题汇总 (XSS + SSRF + 输入校验) + +### 发现清单 + +| 问题 | 位置 | 风险 | +|------|------|------| +| XSS 存储未消毒(患者名/咨询描述) | patient_handler / consultation_handler | Stored XSS | +| dangerouslySetInnerHTML 无消毒 | ArticlePhonePreview.tsx | DOM XSS | +| 空分类名被接受 | article_category_handler | 数据质量 | +| 文章标题超长导致 500 | article_handler | DoS/信息泄漏 | +| API limit 无上限 | 多个 list 端点 | 资源耗尽 | + +### 修复优先级 + +1. **P0 (1h):** 文章标题添加 `#[validate(length(max=255))]` +2. **P1 (2h):** 患者名/咨询描述添加 HTML sanitize +3. **P1 (30min):** ArticlePhonePreview 引入 DOMPurify +4. **P2 (1h):** 所有 list 端点 limit 上限设为 200 +5. **P2 (30min):** 分类名称添加 `#[validate(length(min=1))]` + +--- + +## 6. 议题五: 性能优化路线图 + +### 关键性能指标 + +| 指标 | 当前值 | 目标 | 优先级 | +|------|--------|------|--------| +| Dashboard LCP | 1381ms | < 1000ms | P1 | +| Patient List LCP | 2643ms | < 2000ms | P1 | +| API 重复调用 | ×4 | ×1 | P0 | +| Antd Table Reflow | 460ms | < 100ms | P2 | +| Noto Sans SC | 1.3MB | < 300KB | P2 | + +### 优化方案 + +1. **API 去重 (P0, 4h):** 检查 AdminDashboard useEffect 依赖项,考虑 React Query 缓存 +2. **字体优化 (P2, 1h):** `font-display: optional` + 预加载关键子集 +3. **虚拟滚动 (P2, 2h):** Antd Table `scroll={{ virtual: true }}` +4. **固定 scroll (P2, 1h):** 设置固定 `scroll.x`/`scroll.y` 避免 `measureScrollbarSize` + +--- + +## 7. 议题六: 代码质量提升 + +### 静默吞错治理 + +**原则:** 所有 catch 块至少记录 `console.warn`,关键路径设置错误状态。 + +```typescript +// BAD +.catch(() => {}) + +// GOOD +.catch((err) => { + console.warn('[PatientList] 加载统计数据失败:', err); + // 可选: setErrorState(true) +}) +``` + +### 大文件拆分计划 + +| 文件 | 行数 | 拆分方案 | 优先级 | +|------|------|---------|--------| +| AdminDashboard.tsx | 734 | StatsCards + Charts + ModuleStatus | P2 | +| ArticleManageList.tsx | 654 | FilterBar + ArticleTable + DetailDrawer | P2 | +| FollowUpTaskList.tsx | 543 | TaskFilter + TaskTable + TaskDetail | P3 | + +--- + +## 8. 行动计划与时间线 + +### Phase 0: CRITICAL 修复(Day 1-2,阻塞 Beta) + +| 任务 | 负责方 | 工时 | 依赖 | +|------|--------|------|------| +| C-01: safeGet fallback | 前端 | 1h | — | +| C-02: UTF-8 编码 | 前端 | 2h | — | +| H-01: 患者表单验证 | 前端 | 1h | — | +| H-06: DTO-Entity 映射 | 后端 | 4h | — | +| H-07: 文章标题校验 | 后端 | 30min | — | +| H-02: 预约列表 API | 全栈 | 2h | 需调查根因 | + +### Phase 1: HIGH 修复(Day 3-4) + +| 任务 | 负责方 | 工时 | +|------|--------|------| +| C-03/C-04: 移动端卡片视图 | 前端 | 2d | +| H-03: 768px 断点修复 | 前端 | 4h | +| H-05: API 去重 | 前端 | 4h | +| XSS sanitize (患者/咨询) | 后端 | 2h | + +### Phase 2: MEDIUM + 性能优化(Day 5-7) + +| 任务 | 负责方 | 工时 | +|------|--------|------| +| 对比度修复 | 前端 | 30min | +| Dark Mode 卡片 | 前端 | 4h | +| 静默吞错治理 | 前端 | 2h | +| 字体优化 | 前端 | 1h | +| API 输入校验补全 | 后端 | 3h | + +### Phase 3: LOW + 技术债(Beta 后迭代) + +- i18n 迁移(渐进) +- 大文件拆分(渐进) +- 内联样式清理(渐进) +- 类型声明补全(小程序) + +--- + +## 9. 会议结论 + +### Beta 发布条件 + +**必须在 Phase 0 + Phase 1 完成后才能发布 Beta 版本:** + +1. ✅ 4 个 CRITICAL 全部修复 +2. ✅ 8 个 HIGH 全部修复 +3. ✅ 所有修复通过回归测试 +4. ✅ `cargo check` + `cargo test` + `pnpm build` 全部通过 +5. ✅ 浏览器 + 小程序手动验证核心流程 + +### 预计时间线 + +- **Phase 0:** Day 1-2 (CRITICAL + HIGH 后端) +- **Phase 1:** Day 3-4 (移动端 + API 去重 + XSS) +- **Beta 发布:** Day 4 结束 +- **Phase 2:** Day 5-7 (MEDIUM + 性能) +- **正式版 V1:** Day 7+ (根据 Beta 反馈) diff --git a/docs/audits/v3-beta/08-beta-checklist.md b/docs/audits/v3-beta/08-beta-checklist.md new file mode 100644 index 0000000..416dc9c --- /dev/null +++ b/docs/audits/v3-beta/08-beta-checklist.md @@ -0,0 +1,142 @@ +# Beta 就绪验收清单 + +> 基于 V3 Beta 综合测试发现 | 更新: 2026-05-21 +> 目标: 明确 Beta 发布前的必须完成项和验证标准 + +## 1. 阻塞项(必须修复)— Phase 0 + +### 1.1 小程序认证链路 + +- [ ] **C-01:** `services/request.ts` 的 `safeGet` 添加明文键 fallback 逻辑 +- [ ] **C-02:** `utils/secure-storage.ts` 的 `toBase64/fromBase64` 改用 `TextEncoder/TextDecoder` +- [ ] 验证: 小程序内体征保存、签到、咨询列表 API 调用成功 +- [ ] 验证: 含中文的 `user_data` 加密存储后解密正确 + +### 1.2 Web 前端核心功能 + +- [ ] **H-01:** `PatientList.tsx` 创建表单添加 `form.validateFields()` 前端校验 +- [ ] **H-02:** 预约列表 API 网络异常排查修复 +- [ ] 验证: 空表单提交被前端拦截,显示校验错误 +- [ ] 验证: 预约列表页正常加载数据 + +### 1.3 后端数据完整性 + +- [ ] **H-06:** 日常监测 DTO-Entity 字段映射修复 +- [ ] **H-07:** 文章标题 DTO 添加 `#[validate(length(max=255))]` +- [ ] 验证: 血压/心率/血糖写入后能正确读回 +- [ ] 验证: 500 字符标题返回 400 而非 500 + +## 2. HIGH 项(应该修复)— Phase 1 + +### 2.1 移动端响应式 + +- [ ] **C-03:** Mobile 375px 添加卡片/列表视图替代表格 +- [ ] **C-04:** Mobile 横屏 812×375 内容区域空白修复 +- [ ] **H-03:** Tablet 768px 侧边栏折叠与内容区域同步 +- [ ] 验证: 5 种视口 (1920×1080 / 1366×768 / 768×1024 / 375×812 / 812×375) 全部 PASS + +### 2.2 性能 + +- [ ] **H-04:** 患者列表 LCP 优化至 < 2000ms +- [ ] **H-05:** 仪表盘 API 每个端点从 ×4 降至 ×1 +- [ ] 验证: Lighthouse Desktop Accessibility ≥ 94 + +### 2.3 安全 + +- [ ] 患者名/咨询描述 HTML sanitize +- [ ] ArticlePhonePreview 引入 DOMPurify +- [ ] 验证: XSS payload 存储后不执行 + +## 3. 构建与部署验证 + +### 3.1 后端 + +- [ ] `cargo check --workspace` 无错误 +- [ ] `cargo test --workspace` 全部通过 +- [ ] `cargo clippy -- -D warnings` 无警告 +- [ ] 后端服务正常启动,健康检查 200 + +### 3.2 Web 前端 + +- [ ] `pnpm build` 生产构建通过 +- [ ] `pnpm test` 单元测试通过 +- [ ] 4 种主题切换正常 +- [ ] 所有核心页面加载无 console error + +### 3.3 小程序 + +- [ ] `pnpm build:weapp` 构建通过 +- [ ] 微信开发者工具中 5 个 Tab 页全部可访问 +- [ ] 体征保存、签到、咨询功能正常 +- [ ] 无 JS 异常 + +## 4. 回归测试清单 + +### 4.1 核心业务流程 + +| 流程 | 验证点 | 状态 | +|------|--------|------| +| 登录 → 工作台 | 菜单加载、统计数据显示 | ⬜ | +| 患者创建 | 表单校验、数据保存 | ⬜ | +| 患者搜索 | 关键字过滤生效 | ⬜ | +| 预约列表 | 数据加载、分页 | ⬜ | +| 咨询管理 | 列表、状态切换、评分 | ⬜ | +| 主题切换 | 4 种主题 + 持久化 | ⬜ | + +### 4.2 API 端点抽检 + +| 端点 | 方法 | 验证 | 状态 | +|------|------|------|------| +| /auth/login | POST | 正确/错误密码 | ⬜ | +| /health/patients | GET/POST | CRUD + 校验 | ⬜ | +| /health/daily-monitoring | POST | DTO 映射正确 | ⬜ | +| /health/articles | POST | 标题长度校验 | ⬜ | +| /health/appointments | GET | 列表加载 | ⬜ | + +### 4.3 小程序核心功能 + +| 功能 | 验证点 | 状态 | +|------|--------|------| +| 登录 | Token 获取、存储、读取 | ⬜ | +| 首页 | 体征概览、操作按钮 | ⬜ | +| 体征保存 | 血压写入 + 读回 | ⬜ | +| 签到 | 积分增加 | ⬜ | +| AI 聊天 | 消息发送 | ⬜ | +| 咨询列表 | 数据加载 | ⬜ | + +## 5. 发布签名 + +| 角色 | 确认 | 日期 | +|------|------|------| +| 前端负责人 | ⬜ | — | +| 后端负责人 | ⬜ | — | +| 小程序负责人 | ⬜ | — | +| 安全负责人 | ⬜ | — | +| QA 负责人 | ⬜ | — | +| 产品负责人 | ⬜ | — | + +--- + +## 6. 已知限制(Beta 版本) + +以下问题在 Beta 版本中 **不阻塞**,将在后续迭代中修复: + +1. **移动端响应式** — PC 管理后台移动端体验不佳(有小程序替代) +2. **i18n** — 375 处硬编码中文(国内单语定位) +3. **内联样式** — 1,548 处 `style={{}}`(功能不影响) +4. **API limit 上限** — 无 200 上限(可通过浏览器 DevTools 触发) +5. **重复标签** — 无唯一约束(管理员操作,风险低) +6. **Dark Mode 对比度** — 部分卡片浅色背景(视觉问题,不影响功能) +7. **大文件** — 7 个 500+ 行 TSX 文件(可维护性,非功能问题) + +## 7. 测试报告索引 + +| 章节 | 文件 | 关键发现 | +|------|------|---------| +| 执行摘要 | `01-executive-summary.md` | 36 个问题,B- 评级 | +| Web 功能测试 | `02-web-functional.md` | 8 领域 5 通过,H×2 M×2 | +| 性能/兼容性 | `03-web-perf-compat.md` | Lighthouse 94/100/100,移动端 FAIL | +| 小程序测试 | `04-miniprogram.md` | UI 100%,功能 0%(token 问题) | +| API 深度测试 | `05-api-deep-test.md` | 82.6% 通过率,健康数据 20% | +| 静态分析 | `06-static-analysis.md` | 吞错 10+,i18n 375 处 | +| 头脑风暴 | `07-brainstorm.md` | 3 Phase 修复计划,7 天时间线 | diff --git a/docs/design/mp-device-sync-redesign-preview.png b/docs/design/mp-device-sync-redesign-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..784703235685f0714f70821d65dd140adaf15a13 GIT binary patch literal 278870 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%0DhkQ|#X=eDGufFq_wmeibZiz1Ae8v>2j)fm$ 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

Ovt8{>*FZ6+WtS*C+ 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

YJO$ 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 b$j1l$QY9ZYp~Y8$Umz> + + + + +HMS 小程序 — 设备同步(重新设计) + + + + + + + +

HMS 小程序 · 设备同步(重新设计)
+
7 个状态屏幕:空闲 → 扫描中 → 设备列表 → 连接中 → 已连接(实时数据)→ 同步完成 → 错误状态
+
+ + + + \ No newline at end of file diff --git a/docs/design/mp-device-sync-redesign/META.yml b/docs/design/mp-device-sync-redesign/META.yml new file mode 100644 index 0000000..028e5cd --- /dev/null +++ b/docs/design/mp-device-sync-redesign/META.yml @@ -0,0 +1,12 @@ +prototype: mp-device-sync-redesign.html +source: docs/design/mp-device-sync-redesign.html +variant: patient +generated_at: "2026-05-23T12:00:00+08:00" +tokens: + matched: 23 + unmatched: 2 +components: + total: 12 + mapped: 8 + new: 2 +interactions: 9 diff --git a/docs/design/mp-device-sync-redesign/SPEC.md b/docs/design/mp-device-sync-redesign/SPEC.md new file mode 100644 index 0000000..174b85d --- /dev/null +++ b/docs/design/mp-device-sync-redesign/SPEC.md @@ -0,0 +1,246 @@ +# 设备同步页面 设计规格 + +> 来源: mp-device-sync-redesign.html | 平台: 小程序(患者端) | 页面数: 7 | 生成: 2026-05-23 + +## 页面索引 + +| 页面 | 截图 | 路由 | +|------|------|------| +| 空闲态 | ![空闲态](./screenshots/screen-1.png) | pages/pkg-health/device-sync/index | +| 扫描中 | ![扫描中](./screenshots/screen-2.png) | pages/pkg-health/device-sync/index | +| 设备列表 | ![设备列表](./screenshots/list.png) | pages/pkg-health/device-sync/index | +| 连接中 | ![连接中](./screenshots/screen-4.png) | pages/pkg-health/device-sync/index | +| 已连接 | ![已连接](./screenshots/screen-5.png) | pages/pkg-health/device-sync/index | +| 同步完成 | ![同步完成](./screenshots/screen-6.png) | pages/pkg-health/device-sync/index | +| 错误状态 | ![错误状态](./screenshots/screen-7.png) | pages/pkg-health/device-sync/index | + +## 一、Token 映射 + +| 原型值 | 项目 Token | 状态 | +|--------|-----------|------| +| T.pri (#C4623A) | --tk-pri | ✅ | +| T.priL (#F0DDD4) | --tk-pri-l | ✅ | +| T.priD (#8B3E1F) | --tk-pri-d | ✅ | +| T.bg (#F5F0EB) | $bg SCSS 变量 | ⚠️ 无 CSS Token,直接用 $bg | +| T.card (#FFFFFF) | --tk-card-bg ($card) | ✅ | +| T.surface (#EDE8E2) | --tk-card-bg (≈) | ⚠️ 近似,用 $surface-alt SCSS 变量 | +| T.tx (#2D2A26) | $tx SCSS 变量 | ⚠️ 无 CSS Token,直接用 $tx | +| T.tx2 (#5A554F) | $tx2 SCSS 变量 | ⚠️ 无 CSS Token,直接用 $tx2 | +| T.tx3 (#78716C) | --tk-text-secondary ($tx3) | ✅ | +| T.bd (#E8E2DC) | $bd SCSS 变量 | ⚠️ 无 CSS Token,直接用 $bd | +| T.bdL (#F0EBE5) | $bd-l SCSS 变量 | ⚠️ 无 CSS Token | +| T.acc (#5B7A5E) | $acc SCSS 变量 | ⚠️ 无 CSS Token | +| T.accL (#E8F0E8) | $acc-l SCSS 变量 | ⚠️ 无 CSS Token | +| T.wrn (#C4873A) | $wrn SCSS 变量 | ⚠️ 无 CSS Token | +| T.wrnL (#FFF3E0) | $wrn-l SCSS 变量 | ⚠️ 无 CSS Token | +| T.dan (#B54A4A) | $dan SCSS 变量 | ⚠️ 无 CSS Token | +| T.danL (#FDEAEA) | $dan-l SCSS 变量 | ⚠️ 无 CSS Token | +| T.r (16) | --tk-card-radius ($r) | ✅ | +| T.rSm (12) | $r-sm SCSS 变量 | ⚠️ 无 CSS Token | +| T.rXs (8) | $r-xs SCSS 变量 | ⚠️ 无 CSS Token | +| T.serif (Georgia...) | 字体栈 | ❌ 不映射,直接硬编码 | +| T.sans (-apple-system...) | 字体栈 | ❌ 不映射,直接硬编码 | + +> 状态标记: ✅ confirmed 直接使用 | ⚠️ pending 需 SCSS 变量 | ❌ unmatched 需硬编码 + +## 二、页面结构 + +### 1. 空闲态(idle) + +![空闲态](./screenshots/screen-1.png) + +布局层级(从上到下): +- **NavBar** — 深色主色背景,标题"设备同步" +- **Hero 区域** — 主色渐变背景(135deg pri→priD),包含: + - 蓝牙图标(72px 圆形,半透明白底) + - 标题"智能设备同步"(serif 22px 700) + - 副标题(14px 0.75 白色透明度) +- **支持设备** — 三列标签(心率手环/血压计/血糖仪),每个含 SVG 图标 +- **上次同步卡片** — ContentCard 样式,左侧绿色勾选图标 + 时间 + 右侧数据量 badge +- **待上传提示** — 黄色背景警告条($wrnL),三角感叹号图标 +- **扫描按钮** — 全宽主色按钮,蓝牙图标 + "扫描附近设备" + +### 2. 扫描中(scanning) + +![扫描中](./screenshots/screen-2.png) + +布局层级: +- **NavBar** — 同上 +- **居中脉冲区域**: + - 三层脉冲圆环(CSS animation: pulse-ring),外层→中层→内层递进 + - 中心 80px 圆形蓝牙图标($priL 底色) +- **标题** — serif 20px "正在搜索设备..." +- **副文本** — 14px $tx3 提示文字 +- **进度条** — 180px 宽,渐变填充 $priL→$pri +- **计时文字** — 12px "已用时 6 秒" + +### 3. 设备列表(found) + +![设备列表](./screenshots/list.png) + +布局层级: +- **NavBar** — 同上 +- **结果头部** — 左侧"发现 N 台设备"标题 + 右侧"重新扫描"链接(含刷新图标) +- **设备卡片列表**(×3)— 每张卡片含: + - 左:44px 圆角方块图标($priL 底色 + 蓝牙 SVG) + - 中:设备名(16px 600)+ 适配器类型(12px $tx3) + - 右:信号强度条(4 级竖条) + 箭头 +- **未发现设备提示** — 虚线边框卡片,搜索图标 + 提示文字 + +### 4. 连接中(connecting) + +![连接中](./screenshots/screen-4.png) + +布局层级: +- **NavBar** — 同上 +- **居中动画区域**: + - 100px 旋转环(border-top-color: $pri,CSS animation: connect-spin) + - 60px 中心圆形蓝牙图标 +- **标题** — serif 18px "正在连接 {设备名}" +- **副文本** — "正在进行蓝牙配对..." +- **步骤指示器** — 三点一线:发现设备(✓) → 连接中(●脉冲) → 同步数据(○) + +### 5. 已连接(connected) + +![已连接](./screenshots/screen-5.png) + +布局层级: +- **NavBar** — 同上 +- **连接状态卡片** — 绿色渐变背景(acc→#4A6B4E),蓝牙图标 + 设备名 + "实时" badge +- **最新读数高亮卡片** — 大卡片(r=16 圆角 + shadow),含: + - 52px 心形图标 + - 类型+时间小字 + - 数值(serif 36px 700)+ 单位 +- **历史读数列表** — 标题 + 表格行(类型/数值/时间),每行 12px 分隔线 +- **采集计数** — 居中小字 +- **操作按钮行** — 左侧全宽"上传数据"主色按钮 + 右侧 52px 红色断开按钮 + +### 6. 同步完成(done) + +![同步完成](./screenshots/screen-6.png) + +布局层级: +- **NavBar** — 同上 +- **居中成功区域**: + - 80px 绿色圆形勾选图标 + - 标题"同步完成"(serif 24px 700) + - 副文本"数据已安全上传至健康管理平台" +- **三列统计卡片** — 上传条数(5)/数据类型(3)/成功率(100%) +- **完成按钮** — 全宽主色按钮 + +### 7. 错误状态(error) + +![错误状态](./screenshots/screen-7.png) + +布局层级: +- **NavBar** — 同上 +- **居中错误区域**: + - 80px 红色圆形叉号图标 + - 标题"连接失败"(serif 22px 700) + - 错误描述文字 +- **错误详情卡片** — 含错误码/设备/时间三行键值对 +- **重试按钮** — 全宽主色按钮,含刷新图标 +- **返回按钮** — 描边按钮 + +## 三、组件映射 + +| 原型元素 | 推荐组件 | 来源 | 备注 | +|----------|---------|------|------| +| 页面外壳 | PageShell | @components/ui/PageShell | padding="none",NavBar 自带 | +| 连接状态卡片 | ContentCard | @components/ui/ContentCard | variant="elevated",绿色渐变背景自定义 | +| 成功结果卡片 | ContentCard | @components/ui/ContentCard | variant="elevated",居中布局 | +| 错误详情卡片 | ContentCard | @components/ui/ContentCard | variant="outlined" | +| 扫描按钮/上传按钮 | PrimaryButton | @components/ui/PrimaryButton | size="large",full width | +| 断开连接按钮 | — | 自定义 | 红色小方块图标按钮 | +| 返回按钮 | SecondaryButton | @components/ui/SecondaryButton | — | +| 设备类型标签 | — | 自定义 DeviceTypeTag | 小图标+文字,$bdL 边框 | +| 信号强度 | — | 自定义 SignalBars | 4 级竖条 | +| 上次同步信息 | ListItem | @components/ui/ListItem | leftIcon + title + subtitle + extra | +| 历史读数行 | InfoRow | @components/ui/InfoRow | label + value + last | +| 待上传警告 | AlertCard | @components/ui/AlertCard | variant="bordered",黄色 | + +> ⚠️ **需新建**: SignalBars — 4 级竖条信号强度指示器(20 行以内小组件) +> ⚠️ **需新建**: DeviceTypeTag — 设备类型标签(图标+文字,已非常简单,可直接内联) + +## 四、交互规格 + +| 元素 | 交互 | 触发 | 反馈 | 备注 | +|------|------|------|------|------| +| 扫描按钮 | 调用 handleScan | onClick | 按钮变灰+loading,状态→scanning | 触发 BLE 扫描 | +| 设备卡片 | 调用 handleConnect | onClick | 状态→connecting,显示旋转动画 | 传递选中的 BLEDevice | +| 重新扫描链接 | 调用 handleScan | onClick | 同扫描按钮 | 刷新设备列表 | +| 上传数据按钮 | 调用 handleSync | onClick | 状态→syncing → done/error | 上传采集数据到后端 | +| 断开连接按钮 | 调用 handleDisconnect | onClick | 断开 BLE,状态→idle | 清空 liveReadings | +| 完成按钮 | handleDisconnect + navigateBack | onClick | 返回上一页 | 如果 returnTo=input 则回填 Storage | +| 重试按钮 | handleScan | onClick | 重新扫描 | 从 error 恢复 | +| 返回按钮 | Taro.navigateBack | onClick | 返回上一页 | 错误状态 | +| 实时数据面板 | 被动更新 | BLE 通知 | 新数据插入列表顶部,数值动画 | useBLEManager hook 驱动 | + +## 五、状态变体 + +- **idle**: 默认状态,展示 Hero + 设备类型 + 上次同步 + 扫描按钮 +- **scanning**: 脉冲动画 + 进度条 + 计时,不可操作(无按钮) +- **found**: 设备列表 + 重新扫描链接,点击设备进入 connecting +- **connecting**: 旋转环动画 + 步骤指示器,不可操作 +- **connected**: 绿色连接状态卡 + 实时数据面板 + 上传/断开按钮 +- **done**: 成功图标 + 统计卡片 + 完成按钮 +- **error**: 错误图标 + 错误详情 + 重试/返回按钮 +- **syncing**: 复用 scanning 的加载态样式,文字改为"正在上传数据..." + +## 六、样式清单 + +### 关键样式参数 + +``` +/* Hero 渐变 */ +background: linear-gradient(135deg, $pri 0%, $pri-d 100%) +padding: 32px 20px 28px + +/* 脉冲圆环 */ +animation: pulse-ring 2s ease-out infinite +三层: 140px / 110px / 80px (center) + +/* 旋转环 */ +animation: connect-spin 1s linear infinite +border-top-color: $pri + +/* 最新读数数值 */ +font-family: $serif; font-size: 36px; font-weight: 700 + +/* 连接状态卡片渐变 */ +background: linear-gradient(135deg, $acc 0%, #4A6B4E 100%) + +/* 信号条 */ +4 根竖条: height [4, 7, 10, 13]px, width: 3px, gap: 2px +活跃色: $acc, 非活跃: $bd + +/* 主按钮 */ +background: $pri; border-radius: $r-sm; padding: 16px; +box-shadow: 0 4px 16px rgba(196, 98, 58, 0.3) +``` + +### 字号映射 + +| 原型字号 | Token | 用途 | +|---------|-------|------| +| 36px | 超大数值,直接用 serif bold | 最新读数数值 | +| 28px | --tk-font-h1 | 统计卡片数值 | +| 24px | — | 成功/错误标题 | +| 22px | --tk-font-h2 | Hero 标题、连接中标题 | +| 20px | — | 历史读数数值 | +| 18px | --tk-font-body-lg | NavBar 标题、按钮文字 | +| 17px | — | 主按钮文字 | +| 16px | --tk-font-body | 设备名、按钮文字 | +| 15px | — | 完成页副文本 | +| 14px | --tk-font-body-sm | 副文本、描述、列表类型 | +| 13px | --tk-font-cap | 标签文字、小字 | +| 12px | — | 时间、提示 | + +--- + +> 此规格由 design-handoff skill 自动生成。LLM 实施时请: +> 1. 先阅读截图建立视觉印象 +> 2. 按 Token 映射表使用项目 Token(✅ 标记的直接用,⚠️ 用 SCSS 变量) +> 3. 优先使用"组件映射"中列出的已有组件 +> 4. 参考"交互规格"实现对应的交互逻辑 +> 5. "需新建"的组件参考截图和布局描述从头实现 diff --git a/docs/discussions/2026-05-20-miniprogram-production-ready-brainstorm.md b/docs/discussions/2026-05-20-miniprogram-production-ready-brainstorm.md new file mode 100644 index 0000000..e71e078 --- /dev/null +++ b/docs/discussions/2026-05-20-miniprogram-production-ready-brainstorm.md @@ -0,0 +1,104 @@ +# 小程序上线前五专家组深度审计 + 头脑风暴 + +> 日期: 2026-05-20 | 参与者: UX/UI 审计 / 性能稳定性 / 安全审计 / 产品架构 / 代码质量 + +## 背景 + +小程序(62 页面 + 34 组件 + 38 service)即将交付用户测试。启动 5 个并行专家组进行全方位深度审计,确保交付版本的质量和可用性。 + +## 五专家组综合评分 + +| 专家组 | 评分 | CRITICAL | HIGH | MEDIUM | LOW | 总问题数 | +|--------|------|----------|------|--------|-----|----------| +| UX/UI 审计 | 6.2/10 B- | 3 | 8 | 14 | 9 | 34 | +| 性能稳定性 | 6.5/10 B- | 1 | 4 | 10 | 8 | 25 | +| 安全审计 | 5.1/10 D+ | 2 | 5 | 8 | 6 | 21 | +| 产品架构 | 6.0/10 C+ | 2 | 6 | 8 | 5 | 21 | +| 代码质量 | — | 0 | 2 | 3 | 0 | 134 空 catch + 10 any | +| **综合** | **6.0/10 C+** | **8** | **25** | **43** | **28** | **~135+** | + +## CRITICAL 汇总(必须修复,阻断用户测试) + +| # | 来源 | 问题 | 影响 | +|---|------|------|------| +| 1 | 产品 | 咨询创建页缺失,"发起咨询"按钮导航失败 | 核心咨询流程阻断 | +| 2 | 产品 | 随访流程不闭环(患者无触发入口 + 医生无执行页面) | 医疗质量核心链路断裂 | +| 3 | 安全 | 硬编码管理员凭据 `admin/Admin@2026` 在源码中 | 反编译可获取管理员权限 | +| 4 | 安全 | Token 明文存储在 Storage(secure-storage 实际无加密) | 设备丢失 = 身份冒用 | +| 5 | UX | AI 聊天页 13 处硬编码字号,长者模式完全失效 | TabBar 核心页老年用户不可用 | +| 6 | UX | 咨询详情页 14 处硬编码字号 | 医患沟通场景老年患者无法阅读 | +| 7 | UX | Loading 文字 28px 过大,误认为标题 | 视觉层级混乱 | +| 8 | 性能 | 咨询页长轮询可能永远不启动(dataLoadedRef 时序竞争) | 咨询消息收不到 | + +## HIGH 汇总(严重影响体验,应在上线前修复) + +| # | 来源 | 问题 | +|---|------|------| +| 1 | 产品 | "消息" Tab 实为 AI 聊天,非消息中心,命名误导 | +| 2 | 产品 | 预约创建未选就诊人,多就诊人场景不可用 | +| 3 | 产品 | 趋势图仅 7 天柱状图,缺长期趋势和对比 | +| 4 | 产品 | 日常监测/设备同步入口层级过深 | +| 5 | UX | 87 处页面硬编码字号,长者模式系统性失效 | +| 6 | UX | StatusTag 色值与设计系统不一致 | +| 7 | UX | 44 个页面缺少 ErrorState | +| 8 | UX | AI 聊天页未使用 PageShell 组件 | +| 9 | 安全 | X-Patient-Id/X-Tenant-Id Header 可能导致越权 | +| 10 | 安全 | openid 明文存储和跨网络传输 | +| 11 | 安全 | RichText XSS 绕过风险 | +| 12 | 性能 | 主包 12 页面可能超 2MB,无法发布 | +| 13 | 性能 | 无虚拟滚动,长列表性能差 | +| 14 | 性能 | 首页 4 个并行 API 无批量优化 | +| 15 | 代码 | 134 处空 catch 静默吞错 | + +## 头脑风暴 — 上线策略 + +### 方案 A: 保守上线(修复所有 CRITICAL + 安全加固) + +**时间**: 3-4 天 +**范围**: 8 个 CRITICAL + 安全 TOP 3 +**风险**: HIGH 级别问题可能影响用户第一印象 + +### 方案 B: 全面打磨(修复 CRITICAL + HIGH + 关键 MEDIUM) + +**时间**: 7-10 天 +**范围**: 全部 CRITICAL + HIGH + 选定 MEDIUM +**风险**: 延迟用户测试,但交付质量更高 + +### 方案 C: 分层交付(推荐) + +**时间**: 分 3 批,每批 2-3 天 +**范围**: +- **Batch 1 (P0, 2天)**: 安全 CRITICAL + 功能 CRITICAL + 性能 CRITICAL +- **Batch 2 (P1, 2天)**: UX 一致性 + 长者模式修复 + HIGH 级产品问题 +- **Batch 3 (P2, 3天)**: MEDIUM 级优化 + 性能优化 + 代码质量 + +## 决策 + +采用**方案 C 分层交付**,优先确保安全和功能完整,然后打磨体验。 + +### Batch 1 修复清单(P0, 预估 2 天) + +1. 移除硬编码凭据 → 环境变量注入(1h) +2. 确认后端不信任前端 Header(2h) +3. 咨询创建页缺失 → 新增页面或移除入口按钮(4h) +4. 咨询页长轮询启动时序修复(2h) +5. Loading 文字 token 修正(0.5h) +6. Token 存储安全加固(4h)— 可延至 Batch 2 + +### Batch 2 修复清单(P1, 预估 2 天) + +7. AI 聊天页 + 咨询详情页字号 token 替换(4h) +8. 医生端核心页面字号 token 替换(3h) +9. StatusTag 色值对齐设计系统(1h) +10. AI 聊天页接入 PageShell(2h) +11. 移除 forceSetAuth bridge(0.5h) +12. 随访流程闭环补全(4h)— 可延至 Batch 3 + +### Batch 3 修复清单(P2, 预估 3 天) + +13. 全局 87 处硬字号 → token 批量替换 +14. 74 处硬 padding → token 批量替换 +15. 44 个页面补充 ErrorState +16. 主包瘦身 + splitChunks 配置 +17. 空 catch 添加日志 +18. AI 聊天历史持久化(接后端 API) diff --git a/docs/discussions/2026-05-22-my-page-subpages-necessity.md b/docs/discussions/2026-05-22-my-page-subpages-necessity.md new file mode 100644 index 0000000..4431cb6 --- /dev/null +++ b/docs/discussions/2026-05-22-my-page-subpages-necessity.md @@ -0,0 +1,92 @@ +# 小程序"我的"页面子页面必要性分析 + +> 日期: 2026-05-22 | 参与者: 产品经理 / UX 研究员 / UX 架构师 / 医疗业务专家 / 前端技术专家 + +## 背景 + +小程序患者端"我的"页面当前有 5 个分组共 19 个菜单入口 + 1 个消息通知独立入口 = 20 个可点击项。远超移动端认知负荷上限(7±2),需要从全局角度分析各子页面的存在必要性。 + +## 讨论要点 + +### 核心问题诊断 + +1. **功能堆砌**:把所有没有找到更好归属的功能都塞进"我的",导致它变成了"功能大全"而非"个人中心" +2. **入口重复**:4 个入口在其他 Tab 已有更自然的路径(积分商城、用药记录、在线咨询、我的报告) +3. **透析噪音**:透析管理 3 个入口对所有用户无条件展示,80%+ 非透析用户看到无关功能 +4. **语义模糊**:健康记录/我的报告/诊断记录三入口,患者分不清区别 +5. **性能浪费**:消息未读数请求 50 条列表而非 count 接口 +6. **静态菜单**:无法按患者画像动态显示 + +### 各入口使用频率评估 + +| 频率 | 入口 | +|------|------| +| 高频(日活) | 消息通知、用药记录(慢病) | +| 中频(周活) | 我的预约、我的随访、在线咨询、积分商城 | +| 低频(月活) | 我的报告、健康记录、AI 分析、诊断记录、就诊人管理 | +| 极低频 | 透析处方、知情同意、线下活动、长辈模式、设备同步、设置 | + +### 患者画像与功能需求矩阵 + +| 功能 | 普通体检者(50-60%) | 慢病患者(20-25%) | 透析患者(5-8%) | 术后随访(10-15%) | +|------|:---:|:---:|:---:|:---:| +| 我的报告 | 高 | 高 | 高 | 高 | +| 我的预约 | 高 | 中 | 中 | 中 | +| AI 分析 | 高 | 高 | 中 | 高 | +| 健康记录 | 中 | 高 | 中 | 高 | +| 用药记录 | 低 | 高 | 高 | 中 | +| 我的随访 | 低 | 高 | 中 | 高 | +| 透析管理 | 无 | 无 | 高 | 无 | +| 诊断记录 | 低 | 中 | 中 | 高 | + +## 结论 + +### 共识意见 + +1. **入口数应从 20 缩减到 9-11 个**(常驻 9 + 动态 1-2) +2. **移除 4 个重复入口**:积分商城(TabBar已有)、用药记录(健康Tab已有)、在线咨询(助手Tab可达)、我的报告("我的"保留但健康Tab快捷入口改为AI分析) +3. **透析管理按需显示**:仅透析患者可见,三入口合并为一 +4. **健康数据合并**:健康记录+诊断记录合并为"健康档案"(Tab切换) +5. **长辈模式降级**:从一级入口移入设置页 + +### 优化后菜单结构 + +``` +[消息通知] ← 优化为 getUnreadCount() + +健康档案 + ├── 我的报告(Tab: 检查报告 / AI 解读) + └── 健康档案(Tab: 体检记录 / 诊断记录) + +就诊服务 + ├── 我的预约 + ├── 我的随访 + └── 在线咨询 + +透析管理 ← 仅透析患者可见 + └── (内页 Tab: 透析记录 / 透析处方 / 同意书) + +账号 + ├── 就诊人管理 + ├── 设备同步 + └── 设置(含长辈模式开关) +``` + +### 行动优先级 + +| 优先级 | 行动 | 预期效果 | 工期 | +|--------|------|---------|------| +| P0 | 未读消息改用 getUnreadCount() | 节省 500ms+ | 0.5天 | +| P0 | 移除 3 个重复入口 | 减少 3 个入口 | 0.5天 | +| P1 | 透析管理条件显示 | 80%用户减少3个无关入口 | 1-2天 | +| P1 | 透析三页合并为一 | 节省 20-30KB | 1-2天 | +| P1 | 抽取 usePaginatedList hook | 消除 300 行重复代码 | 1天 | +| P2 | 健康记录/诊断合并为健康档案 | 减少 2 个入口 | 1-2天 | +| P2 | 长辈模式降级到设置页 | 减少 1 个入口 | 0.5天 | +| P2 | 线下活动改为消息推送触达 | 减少 1 个入口 | 0.5天 | + +### 待定 + +- 后端 `patient` 表是否已有 `patient_type` 字段?需确认才能实现动态菜单 +- AI 分析是否应完全合并到"我的报告"Tab,还是保留独立入口? +- 设备同步最终放在"账号"组还是"健康"Tab? diff --git a/docs/健康管理/HMS系统设计思路.md b/docs/健康管理/HMS系统设计思路.md index b0a7bda..b948201 100644 --- a/docs/健康管理/HMS系统设计思路.md +++ b/docs/健康管理/HMS系统设计思路.md @@ -60,7 +60,7 @@ HMS 平台的设计围绕一个核心命题:**让患者的健康数据产生 └──────────────┼───────────────┘ │ ┌─────────┴─────────┐ - │ 统一 API 网关 │ + │ 统一 API 网关 │ │ /api/v1/* │ │ + /api/v1/fhir/* │ └─────────┬─────────┘