Files
digital-pilates/store/checkinSlice.ts
richarjiang f3e6250505 feat: 添加训练计划和打卡功能
- 新增训练计划页面,允许用户制定个性化的训练计划
- 集成打卡功能,用户可以记录每日的训练情况
- 更新 Redux 状态管理,添加训练计划相关的 reducer
- 在首页中添加训练计划卡片,支持用户点击跳转
- 更新样式和布局,以适应新功能的展示和交互
- 添加日期选择器和相关依赖,支持用户选择训练日期
2025-08-13 09:10:00 +08:00

79 lines
2.6 KiB
TypeScript

import { createSlice, PayloadAction } from '@reduxjs/toolkit';
export type CheckinExercise = {
key: string;
name: string;
category: string;
sets: number; // 组数
reps?: number; // 每组重复(计次型)
durationSec?: number; // 每组时长(计时型)
completed?: boolean; // 是否已完成该动作
};
export type CheckinRecord = {
id: string;
date: string; // YYYY-MM-DD
items: CheckinExercise[];
note?: string;
};
export type CheckinState = {
byDate: Record<string, CheckinRecord>;
currentDate: string | null;
};
const initialState: CheckinState = {
byDate: {},
currentDate: null,
};
function ensureRecord(state: CheckinState, date: string): CheckinRecord {
if (!state.byDate[date]) {
state.byDate[date] = {
id: `rec_${date}`,
date,
items: [],
};
}
return state.byDate[date];
}
const checkinSlice = createSlice({
name: 'checkin',
initialState,
reducers: {
setCurrentDate(state, action: PayloadAction<string>) {
state.currentDate = action.payload; // 期望格式 YYYY-MM-DD
ensureRecord(state, action.payload);
},
addExercise(state, action: PayloadAction<{ date: string; item: CheckinExercise }>) {
const rec = ensureRecord(state, action.payload.date);
// 若同 key 已存在则覆盖参数(更接近用户“重新选择/编辑”的心智)
const idx = rec.items.findIndex((it) => it.key === action.payload.item.key);
const normalized: CheckinExercise = { ...action.payload.item, completed: false };
if (idx >= 0) rec.items[idx] = normalized; else rec.items.push(normalized);
},
removeExercise(state, action: PayloadAction<{ date: string; key: string }>) {
const rec = ensureRecord(state, action.payload.date);
rec.items = rec.items.filter((it) => it.key !== action.payload.key);
},
toggleExerciseCompleted(state, action: PayloadAction<{ date: string; key: string }>) {
const rec = ensureRecord(state, action.payload.date);
const idx = rec.items.findIndex((it) => it.key === action.payload.key);
if (idx >= 0) rec.items[idx].completed = !rec.items[idx].completed;
},
setNote(state, action: PayloadAction<{ date: string; note: string }>) {
const rec = ensureRecord(state, action.payload.date);
rec.note = action.payload.note;
},
resetDate(state, action: PayloadAction<string>) {
delete state.byDate[action.payload];
},
},
});
export const { setCurrentDate, addExercise, removeExercise, toggleExerciseCompleted, setNote, resetDate } = checkinSlice.actions;
export default checkinSlice.reducer;