安全修复: - H1: Token 刷新竞态条件 → Singleton Promise 模式防止并发刷新 - H4: 移除 store 中的 token 明文状态,统一走 secure storage - H5: 登录/绑定手机号添加 loading 防重复点击保护 - H6: Analytics 改用 request.ts 统一请求层,不再绕过认证 - M1: logout 清理所有残留数据(openid/tenant_id/analytics_queue) - M2/M7: 敏感数据(user/openid/tenant_id)统一走加密存储 - M3: 移除开发日志中的请求体打印 - M4: secure-storage 解密失败返回 null 而非空串 功能修复: - F1: 今日体征概览 API 支持 patient_id 查询参数(后端+前端) - F2: 积分商城对无患者档案用户展示引导 UI - M6: daily-monitoring 添加 Zod 数值范围验证 清理: - L4: 移除 devLogin 开发辅助函数
56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
import { create } from 'zustand';
|
|
import Taro from '@tarojs/taro';
|
|
import * as healthApi from '@/services/health';
|
|
|
|
interface CachedTrend {
|
|
data: { date: string; value: number }[];
|
|
cachedAt: number;
|
|
}
|
|
|
|
interface HealthState {
|
|
todaySummary: healthApi.TodaySummary | null;
|
|
trendData: Record<string, CachedTrend>;
|
|
loading: boolean;
|
|
refreshToday: () => Promise<void>;
|
|
getTrend: (indicator: string, range: string) => Promise<{ date: string; value: number }[]>;
|
|
clearCache: () => void;
|
|
}
|
|
|
|
const CACHE_TTL = 5 * 60 * 1000; // 5 分钟
|
|
|
|
export const useHealthStore = create<HealthState>((set, get) => ({
|
|
todaySummary: null,
|
|
trendData: {},
|
|
loading: false,
|
|
|
|
refreshToday: async () => {
|
|
set({ loading: true });
|
|
try {
|
|
const patientId = Taro.getStorageSync('current_patient_id') || undefined;
|
|
const data = await healthApi.getTodaySummary(patientId);
|
|
set({ todaySummary: data, loading: false });
|
|
} catch {
|
|
set({ loading: false });
|
|
}
|
|
},
|
|
|
|
getTrend: async (indicator: string, range: string) => {
|
|
const cacheKey = `${indicator}_${range}`;
|
|
const cached = get().trendData[cacheKey];
|
|
if (cached && Date.now() - cached.cachedAt < CACHE_TTL) {
|
|
return cached.data;
|
|
}
|
|
|
|
try {
|
|
const resp = await healthApi.getTrend(indicator, range);
|
|
const points = resp.data_points || [];
|
|
set((s) => ({ trendData: { ...s.trendData, [cacheKey]: { data: points, cachedAt: Date.now() } } }));
|
|
return points;
|
|
} catch {
|
|
return [];
|
|
}
|
|
},
|
|
|
|
clearCache: () => set({ trendData: {}, todaySummary: null }),
|
|
}));
|