feat: 更新 AI 教练聊天界面和个人信息页面

- 在 AI 教练聊天界面中添加训练记录分析功能,允许用户基于近期训练记录获取分析建议
- 更新 Redux 状态管理,集成每日步数和卡路里目标
- 在个人信息页面中优化用户头像显示,支持从库中选择头像
- 修改首页布局,添加可拖动的教练徽章,提升用户交互体验
- 更新样式以适应新功能的展示和交互
This commit is contained in:
richarjiang
2025-08-13 10:09:55 +08:00
parent f3e6250505
commit 5814044cee
8 changed files with 278 additions and 54 deletions

View File

@@ -12,6 +12,9 @@ export type UserProfile = {
weightKg?: number;
heightCm?: number;
avatarUri?: string | null;
dailyStepsGoal?: number; // 每日步数目标(用于 Explore 页等)
dailyCaloriesGoal?: number; // 每日卡路里消耗目标
pilatesPurposes?: string[]; // 普拉提目的(多选)
};
export type UserState = {
@@ -21,10 +24,12 @@ export type UserState = {
error: string | null;
};
export const DEFAULT_MEMBER_NAME = '普拉提星球学员';
const initialState: UserState = {
token: null,
profile: {
fullName: DEFAULT_MEMBER_NAME,
},
loading: false,
error: null,
@@ -94,6 +99,15 @@ const userSlice = createSlice({
updateProfile(state, action: PayloadAction<Partial<UserProfile>>) {
state.profile = { ...(state.profile ?? {}), ...action.payload };
},
setDailyStepsGoal(state, action: PayloadAction<number>) {
state.profile = { ...(state.profile ?? {}), dailyStepsGoal: action.payload };
},
setDailyCaloriesGoal(state, action: PayloadAction<number>) {
state.profile = { ...(state.profile ?? {}), dailyCaloriesGoal: action.payload };
},
setPilatesPurposes(state, action: PayloadAction<string[]>) {
state.profile = { ...(state.profile ?? {}), pilatesPurposes: action.payload };
},
},
extraReducers: (builder) => {
builder
@@ -102,6 +116,9 @@ const userSlice = createSlice({
state.loading = false;
state.token = action.payload.token;
state.profile = action.payload.profile;
if (!state.profile?.fullName || !state.profile.fullName.trim()) {
state.profile.fullName = DEFAULT_MEMBER_NAME;
}
})
.addCase(login.rejected, (state, action) => {
state.loading = false;
@@ -110,6 +127,9 @@ const userSlice = createSlice({
.addCase(rehydrateUser.fulfilled, (state, action) => {
state.token = action.payload.token;
state.profile = action.payload.profile;
if (!state.profile?.fullName || !state.profile.fullName.trim()) {
state.profile.fullName = DEFAULT_MEMBER_NAME;
}
})
.addCase(logout.fulfilled, (state) => {
state.token = null;
@@ -118,7 +138,7 @@ const userSlice = createSlice({
},
});
export const { updateProfile } = userSlice.actions;
export const { updateProfile, setDailyStepsGoal, setDailyCaloriesGoal, setPilatesPurposes } = userSlice.actions;
export default userSlice.reducer;