feat: 更新文章功能和相关依赖
- 新增文章详情页面,支持根据文章 ID 加载和展示文章内容 - 添加文章卡片组件,展示推荐文章的标题、封面和阅读量 - 更新文章服务,支持获取文章列表和根据 ID 获取文章详情 - 集成腾讯云 COS SDK,支持文件上传功能 - 优化打卡功能,支持按日期加载和展示打卡记录 - 更新相关依赖,确保项目兼容性和功能完整性 - 调整样式以适应新功能的展示和交互
This commit is contained in:
@@ -5,9 +5,18 @@ export type CheckinExercise = {
|
||||
key: string;
|
||||
name: string;
|
||||
category: string;
|
||||
sets: number; // 组数
|
||||
/**
|
||||
* itemType
|
||||
* - exercise: 正常训练动作(默认)
|
||||
* - rest: 组间/动作间休息(仅展示,不可勾选完成)
|
||||
* - note: 备注/口令提示(仅展示)
|
||||
*/
|
||||
itemType?: 'exercise' | 'rest' | 'note';
|
||||
sets: number; // 组数(rest/note 可为 0)
|
||||
reps?: number; // 每组重复(计次型)
|
||||
durationSec?: number; // 每组时长(计时型)
|
||||
restSec?: number; // 休息时长(当 itemType=rest 时使用)
|
||||
note?: string; // 备注内容(当 itemType=note 时使用)
|
||||
completed?: boolean; // 是否已完成该动作
|
||||
};
|
||||
|
||||
@@ -16,6 +25,8 @@ export type CheckinRecord = {
|
||||
date: string; // YYYY-MM-DD
|
||||
items: CheckinExercise[];
|
||||
note?: string;
|
||||
// 保留后端原始返回,便于当 metrics.items 为空时做回退展示
|
||||
raw?: any[];
|
||||
};
|
||||
|
||||
export type CheckinState = {
|
||||
@@ -60,10 +71,17 @@ const checkinSlice = createSlice({
|
||||
const rec = ensureRecord(state, action.payload.date);
|
||||
rec.items = rec.items.filter((it) => it.key !== action.payload.key);
|
||||
},
|
||||
replaceExercises(state, action: PayloadAction<{ date: string; items: CheckinExercise[]; note?: string }>) {
|
||||
const rec = ensureRecord(state, action.payload.date);
|
||||
rec.items = (action.payload.items || []).map((it) => ({ ...it, completed: false }));
|
||||
if (typeof action.payload.note === 'string') rec.note = action.payload.note;
|
||||
},
|
||||
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;
|
||||
if (idx >= 0 && (rec.items[idx].itemType ?? 'exercise') === 'exercise') {
|
||||
rec.items[idx].completed = !rec.items[idx].completed;
|
||||
}
|
||||
},
|
||||
setNote(state, action: PayloadAction<{ date: string; note: string }>) {
|
||||
const rec = ensureRecord(state, action.payload.date);
|
||||
@@ -106,20 +124,27 @@ const checkinSlice = createSlice({
|
||||
date,
|
||||
items: mergedItems,
|
||||
note,
|
||||
raw: list,
|
||||
};
|
||||
})
|
||||
.addCase(loadMonthCheckins.fulfilled, (state, action) => {
|
||||
const monthKey = action.payload.monthKey;
|
||||
const merged = action.payload.byDate;
|
||||
for (const d of Object.keys(merged)) {
|
||||
state.byDate[d] = merged[d];
|
||||
const prev = state.byDate[d];
|
||||
const next = merged[d];
|
||||
const items = (next.items && next.items.length > 0) ? next.items : (prev?.items ?? []);
|
||||
const note = (typeof next.note === 'string') ? next.note : prev?.note;
|
||||
const id = next.id || prev?.id || `rec_${d}`;
|
||||
const raw = prev?.raw ?? (next as any)?.raw;
|
||||
state.byDate[d] = { id, date: d, items, note, raw } as CheckinRecord;
|
||||
}
|
||||
state.monthLoaded[monthKey] = true;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const { setCurrentDate, addExercise, removeExercise, toggleExerciseCompleted, setNote, resetDate } = checkinSlice.actions;
|
||||
export const { setCurrentDate, addExercise, removeExercise, replaceExercises, toggleExerciseCompleted, setNote, resetDate } = checkinSlice.actions;
|
||||
export default checkinSlice.reducer;
|
||||
|
||||
// Thunks
|
||||
@@ -145,9 +170,10 @@ export const syncCheckin = createAsyncThunk('checkin/sync', async (record: { dat
|
||||
|
||||
// 获取当天打卡列表(用于进入页面时拉取最新云端数据)
|
||||
export const getDailyCheckins = createAsyncThunk('checkin/getDaily', async (date?: string) => {
|
||||
const list = await fetchDailyCheckins(date);
|
||||
|
||||
return { date, list } as { date?: string; list: any[] };
|
||||
const dateParam = date ?? new Date().toISOString().slice(0, 10);
|
||||
const list = await fetchDailyCheckins(dateParam);
|
||||
try { console.log('getDailyCheckins', { date: dateParam, count: Array.isArray(list) ? list.length : -1 }); } catch { }
|
||||
return { date: dateParam, list } as { date?: string; list: any[] };
|
||||
});
|
||||
|
||||
// 按月加载:优先使用区间接口,失败则逐日回退
|
||||
|
||||
Reference in New Issue
Block a user