目录
技术栈:
①前端VUE
②前端组件库ElementPlus
③后端Springboot
④数据库Mysql
一.el-badge组件、日期选择器
1.核心前端代码
html
<el-date-picker
v-model="todoDate"
type="date"
placeholder="您要查看哪一天的待办?"
style="width: 200px;"
@change="changeDay"
@panel-change="changeMonth"
clearable
>
<!-- 自定义插槽 -->
<template #default="{date}">
<el-badge
:value="unfinishedTask.find(item => item.myDay === (date.getFullYear() + '-' + (date.getMonth() + 1).toString().padStart(2, '0') + '-' + date.getDate().toString().padStart(2, '0')))?.unfishedCount || 0"
class="item"
:offset="[8, 5]"
:is-dot="false"
:hidden="!unfinishedTask.some(item => item.myDay === (date.getFullYear() + '-' + (date.getMonth() + 1).toString().padStart(2, '0') + '-' + date.getDate().toString().padStart(2, '0')))"
>
<!-- <span>{{ date.getFullYear() + '-' + (date.getMonth() + 1).toString().padStart(2, '0') + '-' + date.getDate().toString().padStart(2, '0') }}</span> -->
<span>{{date.getDate()}}</span>
</el-badge>
</template>
</el-date-picker>
2.el-badge徽章组件
value:小红点的数字
offset:小红点的偏移量(可以进行位置微调)
is-dot:为true就只展示小红点;为false可以额外展示数字
hidden:为true就隐藏红点

3.el-date-picker日期选择器
主要理解以下两点:
①自定义插槽<template #default></template>,只有使用这个插槽时,才能给日期面板的每日单元格添加徽章组件,不然你这个el-badge徽章都不知道加在哪里;说白了这个插槽,就代表了每一天的那个单元格。
②@change事件,在日期被切换时触发(比如从2026-01-01切到了2026-01-02号),由于日期切换时,可能直接跨月份,所以需要查询最新月份的每日未完成待办数量;
③@panel-change事件,在日期面板被切换时触发(比如从2025的12月,切换到了2026的1月),我们在这个方法中,查询当前月的每日未完成待办数;
4.核心js代码
javascript
//变量11:当前日期面板所处的月份(举例:2026-01),初始值就是今天所处的年月
const panelMonth = ref(new Date().getFullYear() + '-' + String(new Date().getMonth() + 1).padStart(2, '0'));
//变量12:渲染日期选择器的小红点的对象
const unfinishedTask = ref([]);
//方法14:查询当前月份每天未完成的待办数量
const queryUnfinishedCount = async()=>{
//1.构建入参
const req = {
userId:user.id,
time:panelMonth.value
}
//2.发送请求
const res = await getUnFinishedCount(req);
unfinishedTask.value = res.data;
//3.预览响应结果
//alert(panelMonth.value)
//alert(JSON.stringify(unfinishedTask.value));
}
queryUnfinishedCount();
//方法15:切换月份时(比如从2025年11月切到了2025年12月),要重新查询12月的每天未完成待办数(因为旧数据是11月的每天未完成代办数)
//说白了就是:当日期面板发生变化时,触发的函数
const changeMonth = async(Date)=>{
//1.更新当前日期面板月份panelMonth(变量11)
const year = Date.getFullYear();
const month = Date.getMonth() + 1; // getMonth()返回0-11,需要+1
panelMonth.value = `${year}-${month.toString().padStart(2, '0')}`;
//alert(panelMonth.value)
//2.重新查询当前日期面板所有天的未完成待办数
queryUnfinishedCount();
}
//方法16:日期变化时,触发的事件
const changeDay = (Date)=>{
//1、更新待办列表
doQuery();
//2、更新日期面板未完成待办数
//2-1更新日期面板月份
const year = Date.getFullYear();
const month = Date.getMonth() + 1; // getMonth()返回0-11,需要+1
panelMonth.value = `${year}-${month.toString().padStart(2, '0')}`;
//alert(panelMonth.value);
//2-2重新查询当前日期面板所有天的未完成待办数
queryUnfinishedCount();
}
二.核心SQL
java
@Select("SELECT " +
" DATE(create_time) AS myDay, " +
" COUNT(*) AS unfishedCount " +
"FROM todo_task " +
"WHERE " +
" user_id = #{userId} AND " +
" is_deleted = 0 AND " +
" status IN ('0', '1') AND " +
" DATE_FORMAT(create_time, '%Y-%m') IN ( " +
" DATE_FORMAT(STR_TO_DATE(CONCAT(#{time}, '-01'), '%Y-%m-%d') - INTERVAL 1 MONTH, '%Y-%m'), " +
" #{time}, " +
" DATE_FORMAT(STR_TO_DATE(CONCAT(#{time}, '-01'), '%Y-%m-%d') + INTERVAL 1 MONTH, '%Y-%m') " +
" ) " +
"GROUP BY DATE(create_time)")
public List<Map> getUnFinishedCount(GetUnFinishedCountDto dto);
代码解读:
这个 SQL 查询用于统计用户在指定月份及其前后一个月 中,每天的未完成任务数量。
主要逻辑:
1、查询目标:
- 按日期分组,统计每个日期有多少个未完成的任务
myDay:任务创建日期(仅日期部分)unfishedCount:该日期未完成的任务数量2、筛选条件:
user_id = #{userId}:指定用户
is_deleted = 0:未删除的任务
status IN ('0', '1'):状态为 '0' 或 '1'(代表未完成状态)时间范围:
#{time}参数指定的月份以及前一个月和后一个月(可弥补前端日期面板不显示非当月未完成待办数的缺陷、提高查询效率)3、时间范围逻辑:
#{time}参数格式应为'YYYY-MM'(如:'2024-01')通过
CONCAT(#{time}, '-01')补全为完整日期使用
- INTERVAL 1 MONTH和+ INTERVAL 1 MONTH获取前后月份最终查询 三个月 的数据(前月 + 本月 + 后月)
示例说明:
假设参数为
#{time} = '2024-01',则查询的时间范围包括:
2023年12月(前一个月)
2024年1月(本月)
2024年2月(后一个月)
返回结果示例:
[ {"myDay": "2023-12-15", "unfishedCount": 5}, {"myDay": "2023-12-16", "unfishedCount": 3}, {"myDay": "2024-01-10", "unfishedCount": 8}, ... ]
三.效果展示

本篇文章只是给出了核心代码和思路,具体感兴趣可以自己动手试一试。
以上就是本篇文章的全部内容,喜欢的话可以留个免费的关注呦~~~