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 } from '@/services/request'; interface BindPhoneResp { access_token: string; refresh_token: string; user: { id: string; username: string; display_name?: string; phone?: string; tenant_id?: string }; } interface AuthState { user: { id: string; username: string; display_name?: string; phone?: string; tenant_id?: string } | null; roles: string[]; currentPatient: authApi.PatientInfo | null; patients: authApi.PatientInfo[]; loading: boolean; login: (code: string) => Promise; bindPhone: (encryptedData: string, iv: string) => Promise; setCurrentPatient: (patient: authApi.PatientInfo) => void; loadPatients: () => Promise; logout: () => void; restore: () => void; isMedicalStaff: () => boolean; hasPatientProfile: () => boolean; } export const useAuthStore = create((set, get) => ({ user: null, roles: [], currentPatient: null, patients: [], loading: false, isMedicalStaff: () => { const { roles } = get(); return roles.some((r) => r === 'doctor' || r === 'nurse' || r === 'admin'); }, hasPatientProfile: () => { return !!get().currentPatient; }, restore: () => { let user: AuthState['user'] = null; let roles: string[] = []; try { const userData = secureGet('user_data'); if (userData) user = JSON.parse(userData); const rolesData = secureGet('user_roles'); if (rolesData) roles = JSON.parse(rolesData); } catch { /* secure storage 不可用时保持默认值 */ } const currentPatient = Taro.getStorageSync('current_patient') || null; set({ user, roles, currentPatient }); }, login: async (code: string) => { if (get().loading) return false; set({ loading: true }); try { const resp = await authApi.wechatLogin(code); if (resp.bound && resp.token) { const { access_token, refresh_token, user } = resp.token; const roles = (resp as Record).roles instanceof Array ? ((resp as Record).roles as Array>).map((r) => r.code || r.name || String(r)) : []; secureSet('access_token', access_token); secureSet('refresh_token', refresh_token); secureSet('user_data', JSON.stringify(user)); secureSet('user_roles', JSON.stringify(roles)); secureSet('tenant_id', user.tenant_id || ''); set({ user, roles, loading: false }); return true; } secureSet('wechat_openid', resp.openid); set({ loading: false }); return false; } catch { set({ loading: false }); return false; } }, bindPhone: async (encryptedData: string, iv: string) => { if (get().loading) return false; set({ loading: true }); try { const openid = secureGet('wechat_openid') || ''; if (!openid) { set({ loading: false }); return false; } const resp = await authApi.wechatBindPhone(openid, encryptedData, iv) as Record; const tokenData = resp as { access_token: string; refresh_token: string; user: AuthState['user'] }; const roles = resp.roles instanceof Array ? (resp.roles as Array>).map((r) => r.code || r.name || String(r)) : []; secureSet('access_token', tokenData.access_token); secureSet('refresh_token', tokenData.refresh_token); secureSet('user_data', JSON.stringify(tokenData.user)); secureSet('user_roles', JSON.stringify(roles)); secureSet('tenant_id', tokenData.user?.tenant_id || ''); secureRemove('wechat_openid'); set({ user: tokenData.user, roles, loading: false }); return true; } catch { set({ loading: false }); return false; } }, setCurrentPatient: (patient) => { Taro.setStorageSync('current_patient_id', patient.id); Taro.setStorageSync('current_patient', patient); set({ currentPatient: patient }); }, loadPatients: async () => { try { const patients = await authApi.getPatients(); set({ patients }); if (patients.length > 0 && !get().currentPatient) { get().setCurrentPatient(patients[0]); } } catch { // 患者列表加载失败不阻塞流程 } }, logout: () => { clearRequestCache(); secureRemove('access_token'); secureRemove('refresh_token'); secureRemove('user_data'); secureRemove('user_roles'); secureRemove('tenant_id'); secureRemove('wechat_openid'); Taro.removeStorageSync('current_patient'); Taro.removeStorageSync('current_patient_id'); Taro.removeStorageSync('analytics_queue'); Taro.removeStorageSync('edit_patient'); set({ user: null, roles: [], currentPatient: null, patients: [] }); Taro.redirectTo({ url: '/pages/login/index' }); }, }));