feat: 校验截止日期不能早于起始日期
CI / verify (push) Successful in 1m55s
CI / 部署到服务器 (push) Successful in 29s

- utils/date 新增纯函数 isDateRangeInvalid:任一端为空视为未排期,不判非法
- DatePicker 支持 min 属性,截止日期日历里选不到早于起始日期的日期
- 任务详情抽屉与批量添加面板实时提示,并在保存/提交时拦截
- 看板批量设置截止日期时逐条跳过起始日期更晚的任务,提示里说明跳过数量

测试:新增纯函数、抽屉、批量面板与看板批量四组用例,全量 957 用例通过。
This commit is contained in:
chenshoulin
2026-11-02 16:24:10 +08:00
parent 6d58227614
commit 347ec6fe27
9 changed files with 154 additions and 15 deletions
+19 -3
View File
@@ -4,7 +4,7 @@ import { computed, ref, watch } from 'vue'
import { useTaskStore } from '@/stores/tasks'
import { useToastStore } from '@/stores/toast'
import { COLUMNS, PRIORITY_LABELS, type ColumnId, type Priority, type Task } from '@/types/task'
import { formatDateTime } from '@/utils/date'
import { formatDateTime, isDateRangeInvalid } from '@/utils/date'
import DatePicker from './DatePicker.vue'
import SideDrawer from './SideDrawer.vue'
@@ -56,6 +56,16 @@ watch(
const archived = computed(() => props.task !== null && props.task.archivedAt !== null)
/**
* 日期区间校验:截止日期不能早于起始日期。
*
* 用 computed 而不是「点保存才提示」,是因为两个日期在同一屏里,
* 改完立刻看到红字比按下保存再被打回更顺;保存时仍会再挡一次。
*/
const dateError = computed(() =>
isDateRangeInvalid(startDate.value, dueDate.value) ? '截止日期不能早于起始日期' : null,
)
/**
* 只读时间信息。
*
@@ -123,6 +133,9 @@ function save(): void {
return
}
// 区间非法时不写入,错误提示已由 dateError 实时展示
if (dateError.value) return
store.updateTask(task.id, {
title: trimmed,
description: description.value.trim(),
@@ -245,12 +258,15 @@ function remove(): void {
<div class="flex flex-col gap-1.5">
<span class="text-sm font-medium text-slate-600 dark:text-zinc-400">起始日期</span>
<DatePicker v-model="startDate" />
<DatePicker v-model="startDate" label="起始日期" />
</div>
<div class="flex flex-col gap-1.5">
<span class="text-sm font-medium text-slate-600 dark:text-zinc-400">截止日期</span>
<DatePicker v-model="dueDate" />
<DatePicker v-model="dueDate" label="截止日期" :min="startDate" />
<span v-if="dateError" role="alert" class="text-xs text-rose-600 dark:text-rose-400">
{{ dateError }}
</span>
</div>
<div class="flex flex-col gap-1.5">