- 调整启动画面中的图片宽度,提升视觉效果 - 移除引导页面相关组件,简化应用结构 - 新增心情统计页面,支持用户查看和分析心情数据 - 优化心情卡片组件,增强用户交互体验 - 更新登录页面标题,提升品牌一致性 - 新增心情日历和编辑功能,支持用户记录和管理心情
325 lines
9.9 KiB
TypeScript
325 lines
9.9 KiB
TypeScript
import {
|
|
createMoodCheckin,
|
|
CreateMoodCheckinDto,
|
|
deleteMoodCheckin,
|
|
DeleteMoodCheckinDto,
|
|
getDailyMoodCheckins,
|
|
getMoodCheckinsHistory,
|
|
getMoodStatistics,
|
|
MoodCheckin,
|
|
MoodType,
|
|
updateMoodCheckin,
|
|
UpdateMoodCheckinDto
|
|
} from '@/services/moodCheckins';
|
|
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
import dayjs from 'dayjs';
|
|
|
|
// 状态接口
|
|
interface MoodState {
|
|
// 按日期存储的心情记录
|
|
moodRecords: Record<string, MoodCheckin[]>;
|
|
// 当前选中的日期
|
|
selectedDate: string;
|
|
// 当前选中的心情记录
|
|
selectedMoodRecord: MoodCheckin | null;
|
|
// 加载状态
|
|
loading: {
|
|
daily: boolean;
|
|
history: boolean;
|
|
statistics: boolean;
|
|
create: boolean;
|
|
update: boolean;
|
|
delete: boolean;
|
|
};
|
|
// 错误信息
|
|
error: string | null;
|
|
// 统计数据
|
|
statistics: {
|
|
totalCheckins: number;
|
|
averageIntensity: number;
|
|
moodDistribution: Record<MoodType, number>;
|
|
mostFrequentMood: MoodType | null;
|
|
} | null;
|
|
}
|
|
|
|
// 初始状态
|
|
const initialState: MoodState = {
|
|
moodRecords: {},
|
|
selectedDate: dayjs().format('YYYY-MM-DD'),
|
|
selectedMoodRecord: null,
|
|
loading: {
|
|
daily: false,
|
|
history: false,
|
|
statistics: false,
|
|
create: false,
|
|
update: false,
|
|
delete: false,
|
|
},
|
|
error: null,
|
|
statistics: null,
|
|
};
|
|
|
|
// 异步 actions
|
|
export const fetchDailyMoodCheckins = createAsyncThunk(
|
|
'mood/fetchDailyMoodCheckins',
|
|
async (date: string) => {
|
|
const checkins = await getDailyMoodCheckins(date);
|
|
return { date, checkins };
|
|
}
|
|
);
|
|
|
|
export const fetchMoodHistory = createAsyncThunk(
|
|
'mood/fetchMoodHistory',
|
|
async (params: { startDate: string; endDate: string; moodType?: MoodType }) => {
|
|
const checkins = await getMoodCheckinsHistory(params);
|
|
return { params, checkins };
|
|
}
|
|
);
|
|
|
|
export const fetchMoodStatistics = createAsyncThunk(
|
|
'mood/fetchMoodStatistics',
|
|
async (params: { startDate: string; endDate: string }) => {
|
|
const statistics = await getMoodStatistics(params);
|
|
return statistics;
|
|
}
|
|
);
|
|
|
|
export const createMoodRecord = createAsyncThunk(
|
|
'mood/createMoodRecord',
|
|
async (dto: CreateMoodCheckinDto) => {
|
|
const newRecord = await createMoodCheckin(dto);
|
|
return newRecord;
|
|
}
|
|
);
|
|
|
|
export const updateMoodRecord = createAsyncThunk(
|
|
'mood/updateMoodRecord',
|
|
async (dto: UpdateMoodCheckinDto) => {
|
|
const updatedRecord = await updateMoodCheckin(dto);
|
|
return updatedRecord;
|
|
}
|
|
);
|
|
|
|
export const deleteMoodRecord = createAsyncThunk(
|
|
'mood/deleteMoodRecord',
|
|
async (dto: DeleteMoodCheckinDto) => {
|
|
await deleteMoodCheckin(dto);
|
|
return dto.id;
|
|
}
|
|
);
|
|
|
|
// 创建 slice
|
|
const moodSlice = createSlice({
|
|
name: 'mood',
|
|
initialState,
|
|
reducers: {
|
|
// 设置选中的日期
|
|
setSelectedDate: (state, action: PayloadAction<string>) => {
|
|
state.selectedDate = action.payload;
|
|
// 如果该日期没有记录,设置为 null
|
|
const records = state.moodRecords[action.payload];
|
|
state.selectedMoodRecord = records && records.length > 0 ? records[0] : null;
|
|
},
|
|
// 设置选中的心情记录
|
|
setSelectedMoodRecord: (state, action: PayloadAction<MoodCheckin | null>) => {
|
|
state.selectedMoodRecord = action.payload;
|
|
},
|
|
// 清除错误
|
|
clearError: (state) => {
|
|
state.error = null;
|
|
},
|
|
// 清除统计数据
|
|
clearStatistics: (state) => {
|
|
state.statistics = null;
|
|
},
|
|
// 清除所有数据
|
|
clearMoodData: (state) => {
|
|
state.moodRecords = {};
|
|
state.selectedMoodRecord = null;
|
|
state.statistics = null;
|
|
state.error = null;
|
|
},
|
|
},
|
|
extraReducers: (builder) => {
|
|
// fetchDailyMoodCheckins
|
|
builder
|
|
.addCase(fetchDailyMoodCheckins.pending, (state) => {
|
|
state.loading.daily = true;
|
|
state.error = null;
|
|
})
|
|
.addCase(fetchDailyMoodCheckins.fulfilled, (state, action) => {
|
|
state.loading.daily = false;
|
|
const { date, checkins } = action.payload;
|
|
state.moodRecords[date] = checkins;
|
|
|
|
// 如果是当前选中的日期,更新选中的记录
|
|
if (date === state.selectedDate) {
|
|
state.selectedMoodRecord = checkins.length > 0 ? checkins[0] : null;
|
|
}
|
|
})
|
|
.addCase(fetchDailyMoodCheckins.rejected, (state, action) => {
|
|
state.loading.daily = false;
|
|
state.error = action.error.message || '获取心情记录失败';
|
|
});
|
|
|
|
// fetchMoodHistory
|
|
builder
|
|
.addCase(fetchMoodHistory.pending, (state) => {
|
|
state.loading.history = true;
|
|
state.error = null;
|
|
})
|
|
.addCase(fetchMoodHistory.fulfilled, (state, action) => {
|
|
state.loading.history = false;
|
|
const { checkins } = action.payload;
|
|
|
|
// 将历史记录按日期分组存储
|
|
checkins.forEach(checkin => {
|
|
const date = checkin.checkinDate;
|
|
if (!state.moodRecords[date]) {
|
|
state.moodRecords[date] = [];
|
|
}
|
|
|
|
// 检查是否已存在相同 ID 的记录
|
|
const existingIndex = state.moodRecords[date].findIndex(r => r.id === checkin.id);
|
|
if (existingIndex >= 0) {
|
|
state.moodRecords[date][existingIndex] = checkin;
|
|
} else {
|
|
state.moodRecords[date].push(checkin);
|
|
}
|
|
});
|
|
})
|
|
.addCase(fetchMoodHistory.rejected, (state, action) => {
|
|
state.loading.history = false;
|
|
state.error = action.error.message || '获取心情历史失败';
|
|
});
|
|
|
|
// fetchMoodStatistics
|
|
builder
|
|
.addCase(fetchMoodStatistics.pending, (state) => {
|
|
state.loading.statistics = true;
|
|
state.error = null;
|
|
})
|
|
.addCase(fetchMoodStatistics.fulfilled, (state, action) => {
|
|
state.loading.statistics = false;
|
|
state.statistics = action.payload;
|
|
})
|
|
.addCase(fetchMoodStatistics.rejected, (state, action) => {
|
|
state.loading.statistics = false;
|
|
state.error = action.error.message || '获取心情统计失败';
|
|
});
|
|
|
|
// createMoodRecord
|
|
builder
|
|
.addCase(createMoodRecord.pending, (state) => {
|
|
state.loading.create = true;
|
|
state.error = null;
|
|
})
|
|
.addCase(createMoodRecord.fulfilled, (state, action) => {
|
|
state.loading.create = false;
|
|
const newRecord = action.payload;
|
|
const date = newRecord.checkinDate;
|
|
|
|
// 添加到对应日期的记录中
|
|
if (!state.moodRecords[date]) {
|
|
state.moodRecords[date] = [];
|
|
}
|
|
state.moodRecords[date].unshift(newRecord); // 添加到开头
|
|
|
|
// 如果是当前选中的日期,更新选中的记录
|
|
if (date === state.selectedDate) {
|
|
state.selectedMoodRecord = newRecord;
|
|
}
|
|
})
|
|
.addCase(createMoodRecord.rejected, (state, action) => {
|
|
state.loading.create = false;
|
|
state.error = action.error.message || '创建心情记录失败';
|
|
});
|
|
|
|
// updateMoodRecord
|
|
builder
|
|
.addCase(updateMoodRecord.pending, (state) => {
|
|
state.loading.update = true;
|
|
state.error = null;
|
|
})
|
|
.addCase(updateMoodRecord.fulfilled, (state, action) => {
|
|
state.loading.update = false;
|
|
const updatedRecord = action.payload;
|
|
const date = updatedRecord.checkinDate;
|
|
|
|
// 更新对应日期的记录
|
|
if (state.moodRecords[date]) {
|
|
const index = state.moodRecords[date].findIndex(r => r.id === updatedRecord.id);
|
|
if (index >= 0) {
|
|
state.moodRecords[date][index] = updatedRecord;
|
|
}
|
|
}
|
|
|
|
// 如果是当前选中的记录,更新选中的记录
|
|
if (state.selectedMoodRecord?.id === updatedRecord.id) {
|
|
state.selectedMoodRecord = updatedRecord;
|
|
}
|
|
})
|
|
.addCase(updateMoodRecord.rejected, (state, action) => {
|
|
state.loading.update = false;
|
|
state.error = action.error.message || '更新心情记录失败';
|
|
});
|
|
|
|
// deleteMoodRecord
|
|
builder
|
|
.addCase(deleteMoodRecord.pending, (state) => {
|
|
state.loading.delete = true;
|
|
state.error = null;
|
|
})
|
|
.addCase(deleteMoodRecord.fulfilled, (state, action) => {
|
|
state.loading.delete = false;
|
|
const deletedId = action.payload;
|
|
|
|
// 从所有日期的记录中删除
|
|
Object.keys(state.moodRecords).forEach(date => {
|
|
state.moodRecords[date] = state.moodRecords[date].filter(r => r.id !== deletedId);
|
|
});
|
|
|
|
// 如果是当前选中的记录被删除,清空选中的记录
|
|
if (state.selectedMoodRecord?.id === deletedId) {
|
|
state.selectedMoodRecord = null;
|
|
}
|
|
})
|
|
.addCase(deleteMoodRecord.rejected, (state, action) => {
|
|
state.loading.delete = false;
|
|
state.error = action.error.message || '删除心情记录失败';
|
|
});
|
|
},
|
|
});
|
|
|
|
// 导出 actions
|
|
export const {
|
|
setSelectedDate,
|
|
setSelectedMoodRecord,
|
|
clearError,
|
|
clearStatistics,
|
|
clearMoodData,
|
|
} = moodSlice.actions;
|
|
|
|
// 导出 reducer
|
|
export default moodSlice.reducer;
|
|
|
|
// 导出选择器
|
|
export const selectMoodState = (state: { mood: MoodState }) => state.mood;
|
|
export const selectMoodRecords = (state: { mood: MoodState }) => state.mood.moodRecords;
|
|
export const selectSelectedDate = (state: { mood: MoodState }) => state.mood.selectedDate;
|
|
export const selectSelectedMoodRecord = (state: { mood: MoodState }) => state.mood.selectedMoodRecord;
|
|
export const selectMoodLoading = (state: { mood: MoodState }) => state.mood.loading;
|
|
export const selectMoodError = (state: { mood: MoodState }) => state.mood.error;
|
|
export const selectMoodStatistics = (state: { mood: MoodState }) => state.mood.statistics;
|
|
|
|
// 获取指定日期的心情记录
|
|
export const selectMoodRecordsByDate = (date: string) => (state: { mood: MoodState }) => {
|
|
return state.mood.moodRecords[date] || [];
|
|
};
|
|
|
|
// 获取指定日期的最新心情记录
|
|
export const selectLatestMoodRecordByDate = (date: string) => (state: { mood: MoodState }) => {
|
|
const records = state.mood.moodRecords[date] || [];
|
|
return records.length > 0 ? records[0] : null;
|
|
};
|