feat: Iteration 1 — 审计日志IP记录、文件上传、医护端API、小程序角色切换
Iteration 1 六项任务全部完成: 1. 审计日志IP记录 — task_local RequestInfo 自动注入 IP/user_agent 2. 文件上传服务 — multipart 上传 + ServeDir 静态文件服务 3. 医护端后端API — 医生工作台仪表盘 + 患者标签CRUD + 会话已读 4. 小程序角色切换 — 登录后根据角色跳转医护台/患者首页 5. 小程序安全加固 — secure-storage 开发模式警告 6. 讨论记录归档 — docs/discussions/
This commit is contained in:
@@ -12,7 +12,8 @@ interface BindPhoneResp {
|
||||
interface AuthState {
|
||||
token: string | null;
|
||||
refreshToken: string | null;
|
||||
user: { id: string; username: string; display_name?: string; phone?: string } | null;
|
||||
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;
|
||||
@@ -23,22 +24,30 @@ interface AuthState {
|
||||
loadPatients: () => Promise<void>;
|
||||
logout: () => void;
|
||||
restore: () => void;
|
||||
isMedicalStaff: () => boolean;
|
||||
}
|
||||
|
||||
export const useAuthStore = create<AuthState>((set, get) => ({
|
||||
token: null,
|
||||
refreshToken: null,
|
||||
user: null,
|
||||
roles: [],
|
||||
currentPatient: null,
|
||||
patients: [],
|
||||
loading: false,
|
||||
|
||||
isMedicalStaff: () => {
|
||||
const { roles } = get();
|
||||
return roles.some((r) => r === 'doctor' || r === 'nurse' || r === 'admin');
|
||||
},
|
||||
|
||||
restore: () => {
|
||||
const token = secureGet('access_token') || null;
|
||||
const refreshToken = secureGet('refresh_token') || null;
|
||||
const user = Taro.getStorageSync('user') || null;
|
||||
const roles = Taro.getStorageSync('user_roles') || [];
|
||||
const currentPatient = Taro.getStorageSync('current_patient') || null;
|
||||
set({ token, refreshToken, user, currentPatient });
|
||||
set({ token, refreshToken, user, roles, currentPatient });
|
||||
},
|
||||
|
||||
login: async (code: string) => {
|
||||
@@ -47,11 +56,13 @@ export const useAuthStore = create<AuthState>((set, get) => ({
|
||||
const resp = await authApi.wechatLogin(code);
|
||||
if (resp.bound && resp.token) {
|
||||
const { access_token, refresh_token, user } = resp.token;
|
||||
const roles = (resp as any).roles?.map((r: any) => r.code || r.name || r) || [];
|
||||
secureSet('access_token', access_token);
|
||||
secureSet('refresh_token', refresh_token);
|
||||
Taro.setStorageSync('user', user);
|
||||
Taro.setStorageSync('user_roles', roles);
|
||||
Taro.setStorageSync('tenant_id', (user as any).tenant_id || '');
|
||||
set({ token: access_token, refreshToken: refresh_token, user, loading: false });
|
||||
set({ token: access_token, refreshToken: refresh_token, user, roles, loading: false });
|
||||
return true;
|
||||
}
|
||||
Taro.setStorageSync('wechat_openid', resp.openid);
|
||||
@@ -71,14 +82,16 @@ export const useAuthStore = create<AuthState>((set, get) => ({
|
||||
set({ loading: false });
|
||||
return false;
|
||||
}
|
||||
const resp = await authApi.wechatBindPhone(openid, encryptedData, iv) as BindPhoneResp;
|
||||
const resp = await authApi.wechatBindPhone(openid, encryptedData, iv) as any;
|
||||
const { access_token, refresh_token, user } = resp;
|
||||
const roles = resp.roles?.map((r: any) => r.code || r.name || r) || [];
|
||||
secureSet('access_token', access_token);
|
||||
secureSet('refresh_token', refresh_token);
|
||||
Taro.setStorageSync('user', user);
|
||||
Taro.setStorageSync('user_roles', roles);
|
||||
Taro.setStorageSync('tenant_id', user.tenant_id || '');
|
||||
Taro.removeStorageSync('wechat_openid');
|
||||
set({ token: access_token, refreshToken: refresh_token, user, loading: false });
|
||||
set({ token: access_token, refreshToken: refresh_token, user, roles, loading: false });
|
||||
return true;
|
||||
} catch {
|
||||
set({ loading: false });
|
||||
@@ -108,9 +121,10 @@ export const useAuthStore = create<AuthState>((set, get) => ({
|
||||
secureRemove('access_token');
|
||||
secureRemove('refresh_token');
|
||||
Taro.removeStorageSync('user');
|
||||
Taro.removeStorageSync('user_roles');
|
||||
Taro.removeStorageSync('current_patient');
|
||||
Taro.removeStorageSync('current_patient_id');
|
||||
set({ token: null, refreshToken: null, user: null, currentPatient: null, patients: [] });
|
||||
set({ token: null, refreshToken: null, user: null, roles: [], currentPatient: null, patients: [] });
|
||||
Taro.redirectTo({ url: '/pages/login/index' });
|
||||
},
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user