feat(个人中心): 优化会员横幅组件,支持深色模式与国际化;新增医疗记录卡片组件,完善健康档案功能

This commit is contained in:
richarjiang
2025-12-05 14:35:10 +08:00
parent f3d4264b53
commit 3d08721474
16 changed files with 3771 additions and 2961 deletions

View File

@@ -1,6 +1,13 @@
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import * as healthProfileApi from '@/services/healthProfile';
import { AppDispatch, RootState } from './index';
import {
HistoryData,
HistoryItemDetail,
MedicalRecordItem,
MedicalRecordsData,
MedicalRecordType,
} from '@/services/healthProfile';
// 健康数据类型定义
export interface FitnessRingsData {
@@ -45,6 +52,9 @@ export interface HealthState {
// 健康史数据
historyData: HistoryData;
// 就医资料数据
medicalRecords: MedicalRecordsData;
// 加载状态
loading: boolean;
error: string | null;
@@ -62,6 +72,10 @@ const initialState: HealthState = {
surgery: { hasHistory: null, items: [] },
familyDisease: { hasHistory: null, items: [] },
},
medicalRecords: {
records: [],
prescriptions: [],
},
loading: false,
error: null,
lastUpdateTime: null,
@@ -136,6 +150,34 @@ const healthSlice = createSlice({
familyDisease: { hasHistory: null, items: [] },
};
},
// 更新就医资料列表
setMedicalRecords: (state, action: PayloadAction<MedicalRecordsData>) => {
state.medicalRecords = action.payload;
state.lastUpdateTime = new Date().toISOString();
},
// 添加就医资料项
addMedicalRecordItem: (state, action: PayloadAction<MedicalRecordItem>) => {
const item = action.payload;
if (item.type === 'medical_record') {
state.medicalRecords.records.unshift(item);
} else {
state.medicalRecords.prescriptions.unshift(item);
}
state.lastUpdateTime = new Date().toISOString();
},
// 删除就医资料项
removeMedicalRecordItem: (state, action: PayloadAction<{ id: string; type: MedicalRecordType }>) => {
const { id, type } = action.payload;
if (type === 'medical_record') {
state.medicalRecords.records = state.medicalRecords.records.filter(item => item.id !== id);
} else {
state.medicalRecords.prescriptions = state.medicalRecords.prescriptions.filter(item => item.id !== id);
}
state.lastUpdateTime = new Date().toISOString();
},
},
extraReducers: (builder) => {
builder
@@ -196,6 +238,40 @@ const healthSlice = createSlice({
// 获取健康史进度
.addCase(fetchHealthHistoryProgress.rejected, (state, action) => {
state.error = action.payload as string;
})
// 获取就医资料
.addCase(fetchMedicalRecords.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(fetchMedicalRecords.fulfilled, (state, action) => {
state.loading = false;
state.medicalRecords = action.payload;
state.lastUpdateTime = new Date().toISOString();
})
.addCase(fetchMedicalRecords.rejected, (state, action) => {
state.loading = false;
state.error = action.payload as string;
})
// 添加就医资料
.addCase(addNewMedicalRecord.fulfilled, (state, action) => {
const item = action.payload;
if (item.type === 'medical_record') {
state.medicalRecords.records.unshift(item);
} else {
state.medicalRecords.prescriptions.unshift(item);
}
state.lastUpdateTime = new Date().toISOString();
})
// 删除就医资料
.addCase(deleteMedicalRecordItem.fulfilled, (state, action) => {
const { id, type } = action.payload;
if (type === 'medical_record') {
state.medicalRecords.records = state.medicalRecords.records.filter(item => item.id !== id);
} else {
state.medicalRecords.prescriptions = state.medicalRecords.prescriptions.filter(item => item.id !== id);
}
state.lastUpdateTime = new Date().toISOString();
});
},
});
@@ -210,6 +286,9 @@ export const {
updateHistoryData,
setHistoryData,
clearHistoryData,
setMedicalRecords,
addMedicalRecordItem,
removeMedicalRecordItem,
} = healthSlice.actions;
// Thunk action to fetch and set health data for a specific date
@@ -286,12 +365,60 @@ export const fetchHealthHistoryProgress = createAsyncThunk(
}
);
// ==================== 就医资料 API Thunks ====================
/**
* 获取就医资料
*/
export const fetchMedicalRecords = createAsyncThunk(
'health/fetchMedicalRecords',
async (_, { rejectWithValue }) => {
try {
const data = await healthProfileApi.getMedicalRecords();
return data;
} catch (err: any) {
return rejectWithValue(err?.message ?? '获取就医资料失败');
}
}
);
/**
* 添加就医资料
*/
export const addNewMedicalRecord = createAsyncThunk(
'health/addMedicalRecord',
async (data: Omit<MedicalRecordItem, 'id'>, { rejectWithValue }) => {
try {
const result = await healthProfileApi.addMedicalRecord(data);
return result;
} catch (err: any) {
return rejectWithValue(err?.message ?? '添加就医资料失败');
}
}
);
/**
* 删除就医资料
*/
export const deleteMedicalRecordItem = createAsyncThunk(
'health/deleteMedicalRecord',
async ({ id, type }: { id: string; type: MedicalRecordType }, { rejectWithValue }) => {
try {
await healthProfileApi.deleteMedicalRecord(id);
return { id, type };
} catch (err: any) {
return rejectWithValue(err?.message ?? '删除就医资料失败');
}
}
);
// Selectors
export const selectHealthDataByDate = (date: string) => (state: RootState) => state.health.dataByDate[date];
export const selectHealthLoading = (state: RootState) => state.health.loading;
export const selectHealthError = (state: RootState) => state.health.error;
export const selectLastUpdateTime = (state: RootState) => state.health.lastUpdateTime;
export const selectHistoryData = (state: RootState) => state.health.historyData;
export const selectMedicalRecords = (state: RootState) => state.health.medicalRecords;
// 计算健康史完成度的 selector
export const selectHealthHistoryProgress = (state: RootState) => {