feat: 增加待办提醒筛选和默认开始日期

This commit is contained in:
yueyang 2026-10-27 15:07:28 +08:00
parent 4519a0e627
commit 2396c4bfbc
3 changed files with 79 additions and 4 deletions

View File

@ -19,6 +19,13 @@ use Throwable;
class SystemizationTodos extends Controller
{
private const OVERDUE_FILTER = '__overdue__';
private const REMINDER_OPTIONS = [
'overdue' => '已逾期',
'today' => '今天到期',
'upcoming' => '剩余天数',
'pending' => '时间待定',
'none' => '无提醒',
];
public function page(): array
{
@ -36,6 +43,24 @@ class SystemizationTodos extends Controller
} elseif ($filters['status'] === SystemizationTodo::STATUS_COMPLETED) {
$query->where('status', $filters['status']);
}
if ($filters['reminder'] !== '') {
if ($filters['reminder'] === 'overdue') {
$query->where('status', '<>', SystemizationTodo::STATUS_COMPLETED)
->whereNotNull('due_date')
->whereDate('due_date', '<', today());
} elseif ($filters['reminder'] === 'today') {
$query->where('status', '<>', SystemizationTodo::STATUS_COMPLETED)
->whereDate('due_date', today());
} elseif ($filters['reminder'] === 'upcoming') {
$query->where('status', '<>', SystemizationTodo::STATUS_COMPLETED)
->whereDate('due_date', '>', today());
} elseif ($filters['reminder'] === 'pending') {
$query->where('status', '<>', SystemizationTodo::STATUS_COMPLETED)
->whereNull('due_date');
} elseif ($filters['reminder'] === 'none') {
$query->where('status', SystemizationTodo::STATUS_COMPLETED);
}
}
if ($filters['category'] !== '') {
$query->where('category', $filters['category']);
}
@ -150,6 +175,12 @@ class SystemizationTodos extends Controller
'todoAssignees' => $this->peopleOptions('assignee'),
'todoStatuses' => SystemizationTodo::STATUSES,
'todoStatusOptions' => $statusOptions,
'todoReminderOptions' => collect(self::REMINDER_OPTIONS)
->map(static fn (string $label, string $value): array => [
'value' => $value,
'label' => $label,
])
->values(),
'todoReturnFilters' => base64_encode(json_encode(
$filters,
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,
@ -602,6 +633,7 @@ class SystemizationTodos extends Controller
{
return [
'status' => $this->normalizeStatusValue(request('status')),
'reminder' => $this->normalizeReminderValue(request('reminder')),
'category' => trim((string) request('category', '')),
'owners' => $this->peopleFilter('owner'),
'assignees' => $this->peopleFilter('assignee'),
@ -624,6 +656,13 @@ class SystemizationTodos extends Controller
: '';
}
private function normalizeReminderValue(mixed $value): string
{
$reminder = trim((string) $value);
return array_key_exists($reminder, self::REMINDER_OPTIONS) ? $reminder : '';
}
private function peopleFilter(string $key): array
{
return collect((array) request($key, []))
@ -818,6 +857,7 @@ class SystemizationTodos extends Controller
return array_filter([
'status' => $this->normalizeStatusValue($filters['status'] ?? null),
'reminder' => $this->normalizeReminderValue($filters['reminder'] ?? null),
'category' => $category,
'owner' => $owners,
'assignee' => $assignees,

View File

@ -264,6 +264,12 @@
<option value="{{ $category }}" @selected($todoFilters['category'] === $category)>{{ $category }}</option>
@endforeach
</select></label>
<label>提醒<select name="reminder">
<option value="">全部提醒</option>
@foreach ($todoReminderOptions as $reminderOption)
<option value="{{ $reminderOption['value'] }}" @selected($todoFilters['reminder'] === $reminderOption['value'])>{{ $reminderOption['label'] }}</option>
@endforeach
</select></label>
@php
$selectedOwners = $todoOwners->filter(
static fn (string $owner): bool => in_array($owner, $todoFilters['owners'], true)
@ -595,7 +601,7 @@
<div class="sys-todo-scrollrail__spacer" data-sys-todo-scrollrail-spacer></div>
</div>
<dialog class="sys-todo-dialog" id="sysTodoDialog" aria-labelledby="sysTodoDialogTitle">
<dialog class="sys-todo-dialog" id="sysTodoDialog" aria-labelledby="sysTodoDialogTitle" data-sys-todo-default-start-date="{{ today()->toDateString() }}">
<form method="POST" enctype="multipart/form-data" data-sys-todo-form>
@csrf
<input type="hidden" name="_method" value="POST" data-sys-todo-method>
@ -783,6 +789,7 @@
var dialog = document.getElementById('sysTodoDialog');
var form = dialog.querySelector('[data-sys-todo-form]');
var pageRoot = dialog.closest('.sys-todo-page');
var defaultStartDate = dialog.getAttribute('data-sys-todo-default-start-date') || '';
if (window.CaiWuDatePicker) window.CaiWuDatePicker.setup(pageRoot || document);
var methodInput = dialog.querySelector('[data-sys-todo-method]');
var title = document.getElementById('sysTodoDialogTitle');
@ -1382,7 +1389,7 @@
setCategoryValue('');
refreshSectionOptions('');
setOwnerValue('');
applyDateControl(startDateControl, '', '');
applyDateControl(startDateControl, defaultStartDate, '');
applyDateControl(dueDateControl, '', '');
}
if (!currentTodoId && !(payload && payload.status)) {

View File

@ -34,8 +34,11 @@ class SystemizationTodosTest extends FeatureTestCase
->assertSeeText('开始时间')
->assertSeeText('完成时间')
->assertSeeText('待定')
->assertSee('name="reminder"', false)
->assertSeeText('全部提醒')
->assertSeeText('完成情况 / 备注')
->assertSeeText('提醒')
->assertSee('data-sys-todo-default-start-date', false)
->assertSee('data-sys-todo-inline-add', false)
->assertSee('data-sys-todo-col-resizer', false)
->assertSee('data-sys-todo-reset-columns', false)
@ -478,6 +481,7 @@ class SystemizationTodosTest extends FeatureTestCase
$todo = $this->createTodo('收入', '平台收入核对', '筛选保持测试', '2026-10-30', 1);
$returnFilters = base64_encode(json_encode([
'status' => SystemizationTodo::STATUS_INCOMPLETE,
'reminder' => 'upcoming',
'category' => '收入',
'owners' => ['晨曦', '人参'],
'assignees' => ['栎阳'],
@ -501,6 +505,7 @@ class SystemizationTodosTest extends FeatureTestCase
$location = (string) $response->headers->get('Location');
parse_str((string) parse_url($location, PHP_URL_QUERY), $query);
$this->assertSame(SystemizationTodo::STATUS_INCOMPLETE, $query['status'] ?? null);
$this->assertSame('upcoming', $query['reminder'] ?? null);
$this->assertSame('收入', $query['category'] ?? null);
$this->assertSame(['晨曦', '人参'], $query['owner'] ?? null);
$this->assertSame(['栎阳'], $query['assignee'] ?? null);
@ -526,11 +531,16 @@ class SystemizationTodosTest extends FeatureTestCase
]);
$legacy = $this->createTodo('收入', '提醒测试', '历史进行中事项', '2026-11-01', 5);
$legacy->update(['status' => '进行中']);
$pendingDate = $this->createTodo('收入', '提醒测试', '时间待定事项', '2026-10-30', 6);
$pendingDate->update(['due_date' => null, 'due_note' => '待定']);
$content = $this->get(route('business.pages.show', [
$pageResponse = $this->get(route('business.pages.show', [
'section' => 'other',
'page' => 'systemization-todos',
]))->assertOk()->viewData('content');
]))->assertOk()
->assertSee('data-sys-todo-default-start-date="2026-10-26"', false)
->assertSee("applyDateControl(startDateControl, defaultStartDate, '');", false);
$content = $pageResponse->viewData('content');
$items = $content['items']->keyBy('title');
$this->assertSame('逾期 6 天', $items['逾期事项']->reminder_label);
@ -538,6 +548,7 @@ class SystemizationTodosTest extends FeatureTestCase
$this->assertSame('今天到期', $items['今天到期事项']->reminder_label);
$this->assertSame('剩余 4 天', $items['未来事项']->reminder_label);
$this->assertSame('—', $items['已完成事项']->reminder_label);
$this->assertSame('时间待定', $items['时间待定事项']->reminder_label);
$this->assertSame('', $items['已完成事项']->displayProgress());
$this->assertSame(SystemizationTodo::STATUS_INCOMPLETE, $items['历史进行中事项']->status_label);
@ -555,6 +566,23 @@ class SystemizationTodosTest extends FeatureTestCase
'status' => SystemizationTodo::STATUS_COMPLETED,
]))->assertOk()->viewData('content')['items']->pluck('title');
$this->assertSame(['已完成事项'], $completedTitles->all());
foreach ([
'overdue' => ['逾期事项'],
'today' => ['今天到期事项'],
'upcoming' => ['未来事项', '历史进行中事项'],
'pending' => ['时间待定事项'],
'none' => ['已完成事项'],
] as $reminder => $expectedTitles) {
$reminderContent = $this->get(route('business.pages.show', [
'section' => 'other',
'page' => 'systemization-todos',
'reminder' => $reminder,
]))->assertOk()->viewData('content');
$this->assertSame($reminder, $reminderContent['todoFilters']['reminder']);
$this->assertSame($expectedTitles, $reminderContent['items']->pluck('title')->all());
}
} finally {
Carbon::setTestNow();
}