diff --git a/app/Http/Controllers/Business/SystemizationTodos.php b/app/Http/Controllers/Business/SystemizationTodos.php index 478a9679..4ebd4237 100644 --- a/app/Http/Controllers/Business/SystemizationTodos.php +++ b/app/Http/Controllers/Business/SystemizationTodos.php @@ -101,8 +101,7 @@ class SystemizationTodos extends Controller ->orderBy('due_date') ->orderBy('sort_order') ->orderBy('id') - ->paginate(50) - ->withQueryString(); + ->get(); $base = SystemizationTodo::query(); $categories = SystemizationTodo::query() diff --git a/resources/views/business/pages/systemization-todos.blade.php b/resources/views/business/pages/systemization-todos.blade.php index 6f7d3fd6..8cfe976c 100644 --- a/resources/views/business/pages/systemization-todos.blade.php +++ b/resources/views/business/pages/systemization-todos.blade.php @@ -36,20 +36,16 @@ .sys-todo-filter__multi-menu input[type="checkbox"] { flex:0 0 auto; width:1rem; height:1rem; padding:0; accent-color:var(--sys-gold); } .sys-todo-filter__multi-empty { padding:.65rem; color:#777; font-size:.75rem; text-align:center; } .sys-todo-filter__actions { display:flex; flex:0 0 auto; gap:.45rem; } - .sys-todo-table-wrap { overflow:auto; border:1px solid var(--sys-border); border-radius:.65rem; background:#fff; } - .sys-todo-table-wrap { max-height:clamp(24rem,58vh,46rem); overscroll-behavior:contain; scrollbar-gutter:stable; } - .sys-todo-table { width:100%; min-width:80rem; border-collapse:separate; border-spacing:0; font-size:.75rem; } + .sys-todo-table-wrap { overflow-x:auto; overflow-y:visible; border:1px solid var(--sys-border); border-radius:.65rem; background:#fff; scrollbar-gutter:stable; } + .sys-todo-table { width:100%; min-width:74rem; border-collapse:separate; border-spacing:0; font-size:.75rem; } .sys-todo-table th { position:sticky; top:0; z-index:4; padding:.55rem .48rem; border-bottom:1px solid var(--sys-border); background:#f3ece0; color:#3d3a35; text-align:left; white-space:nowrap; } - .sys-todo-table td { padding:.45rem .48rem; border-bottom:1px solid #eee7da; background:#fff; color:#2f2a23; vertical-align:top; } + .sys-todo-table td { padding:.65rem .55rem; border-bottom:1px solid #eee7da; background:#fff; color:#2f2a23; line-height:1.55; vertical-align:top; } .sys-todo-table tbody tr { cursor:pointer; } .sys-todo-table tbody tr:hover td { background:#fdfbf6; } .sys-todo-table tbody tr:focus-visible { outline:2px solid var(--sys-gold); outline-offset:-2px; } .sys-todo-table__index-cell { width:3.6rem; min-width:3.6rem; text-align:center; } - .sys-todo-table th:last-child, .sys-todo-table td:last-child { position:sticky; right:0; z-index:3; width:5.8rem; min-width:5.8rem; background:#fff; box-shadow:-1px 0 0 #e5ddcf; } - .sys-todo-table th:last-child { z-index:6; background:#f3ece0; } - .sys-todo-table tbody tr:hover td:last-child { background:#fdfbf6; } .sys-todo-table__index { color:#6d5630; font-weight:600; font-variant-numeric:tabular-nums; white-space:nowrap; } - .sys-todo-table__group { vertical-align:middle; background:#fcfaf5; font-weight:600; } + .sys-todo-table__group { padding-top:.8rem; padding-bottom:.8rem; background:#fcfaf5; font-weight:600; line-height:1.65; vertical-align:middle; } .sys-todo-table__section { min-width:11rem; max-width:17rem; } .sys-todo-table__title, .sys-todo-table__progress, .sys-todo-table__notes { line-height:1.45; white-space:pre-line; overflow-wrap:anywhere; } .sys-todo-table__title { min-width:17rem; max-width:24rem; font-weight:600; } @@ -65,17 +61,11 @@ .sys-todo-shots { display:flex; flex-wrap:wrap; gap:.3rem; max-width:13rem; } .sys-todo-shots button { display:block; width:4.25rem; height:3.2rem; padding:0; border:1px solid #ddd4c4; border-radius:.35rem; overflow:hidden; background:#faf8f3; cursor:zoom-in; } .sys-todo-shots img { width:100%; height:100%; object-fit:cover; } - .sys-todo-row-actions { display:flex; flex-wrap:wrap; gap:.35rem; } - .sys-todo-row-actions button, .sys-todo-row-actions a { padding:.2rem .45rem; border:1px solid var(--sys-border); border-radius:.35rem; background:#fff; color:#51483c; font:inherit; font-size:.72rem; text-decoration:none; cursor:pointer; } - .sys-todo-row-actions button:hover, .sys-todo-row-actions a:hover { border-color:#c7b687; background:var(--sys-gold-soft); } .sys-todo-table__add { display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:.65rem; margin-top:.6rem; padding:.55rem .7rem; border:1px dashed #d8cdb8; border-radius:.55rem; background:#fcfaf5; color:#666; font-size:.72rem; } .sys-todo-table__add button { display:inline-flex; align-items:center; gap:.25rem; min-height:2rem; padding:0 .7rem; border:1px solid var(--sys-border); border-radius:.4rem; background:#fff; color:#51483c; font:inherit; font-size:.76rem; cursor:pointer; } .sys-todo-table__add button:hover { border-color:#c7b687; background:var(--sys-gold-soft); } .sys-todo-table__add .material-icons-outlined { font-size:1rem; } .sys-todo-empty { padding:2rem 1rem; color:#777; text-align:center; } - .sys-todo-pagination { display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:.75rem; padding:.85rem 0 0; color:#595959; font-size:.75rem; } - .sys-todo-pagination__actions { display:flex; gap:.5rem; } - .sys-todo-pagination a, .sys-todo-pagination span { padding:.3rem .55rem; border:1px solid var(--sys-border); border-radius:.35rem; background:#fff; color:#171717; text-decoration:none; } .sys-todo-flash { margin:0 0 .85rem; padding:.65rem .85rem; border:1px solid #bad0ac; border-radius:.45rem; background:#f2f8ed; color:#53793e; font-size:.8125rem; } .sys-todo-flash--error { border-color:#e7c3c3; background:#fff3f3; color:#b80000; } .sys-todo-import { margin:0 0 1rem; border:1px solid #e6dfd2; border-radius:.65rem; background:#fcfaf5; } @@ -118,6 +108,19 @@ .sys-todo-dialog__foot { display:flex; justify-content:flex-end; gap:.5rem; padding:.75rem 1.25rem; border-top:1px solid #e8e0d2; background:#fcfaf5; } .sys-todo-dialog__foot button { min-height:2.1rem; padding:0 .9rem; border:1px solid var(--sys-border); border-radius:.45rem; background:#fff; font:inherit; font-size:.8125rem; cursor:pointer; } .sys-todo-dialog__foot button[type="submit"] { border-color:var(--sys-gold); background:var(--sys-gold); color:#fff; } + .sys-todo-dialog__foot .sys-todo-dialog__delete { margin-right:auto; border-color:#e7c3c3; color:#b80000; } + .sys-todo-dialog__foot .sys-todo-dialog__delete:hover { background:#fff3f3; } + .sys-todo-dialog__foot .sys-todo-dialog__delete[hidden] { display:none; } + .sys-todo-confirm { width:min(30rem,calc(100vw - 2rem)); padding:0; border:1px solid var(--sys-border); border-radius:.8rem; background:#fff; color:#171717; overflow:hidden; } + .sys-todo-confirm::backdrop { background:rgba(23,23,23,.58); } + .sys-todo-confirm__head { display:flex; align-items:center; gap:.55rem; padding:.9rem 1rem; border-bottom:1px solid #e8e0d2; background:#fff8f8; color:#b80000; font-weight:600; } + .sys-todo-confirm__head .material-icons-outlined { font-size:1.15rem; } + .sys-todo-confirm__body { padding:1rem; color:#444; font-size:.84rem; line-height:1.7; } + .sys-todo-confirm__body strong { display:block; margin-top:.45rem; color:#171717; font-weight:600; } + .sys-todo-confirm__actions { display:flex; justify-content:flex-end; gap:.5rem; padding:.75rem 1rem; border-top:1px solid #e8e0d2; background:#fcfaf5; } + .sys-todo-confirm__actions button { min-height:2.1rem; padding:0 .9rem; border:1px solid var(--sys-border); border-radius:.45rem; background:#fff; font:inherit; font-size:.8125rem; cursor:pointer; } + .sys-todo-confirm__actions .sys-todo-confirm__submit { border-color:#b80000; background:#b80000; color:#fff; } + .sys-todo-confirm__actions .sys-todo-confirm__submit:hover { background:#920000; } .sys-todo-image-dialog { width:min(72rem,calc(100vw - 2rem)); max-height:92vh; padding:0; border:1px solid var(--sys-border); border-radius:.8rem; background:#111; color:#fff; overflow:hidden; } .sys-todo-image-dialog::backdrop { background:rgba(5,5,6,.78); } .sys-todo-image-dialog__head { display:flex; align-items:center; gap:1rem; padding:.65rem .85rem; background:#1d1d1f; } @@ -129,7 +132,7 @@ .sys-todo-image-dialog__foot a { color:#f0e4bf; font-size:.75rem; } @media (max-width:1300px) { .sys-todo-summary { grid-template-columns:repeat(3,minmax(0,1fr)); } } @media (max-width:900px) { .sys-todo-filter label, .sys-todo-filter label.sys-todo-filter__keyword { flex-basis:9rem; } .sys-todo-filter__actions { width:100%; } .sys-todo-filter__actions .sys-todo-page__button { flex:1; } } - @media (max-width:720px) { .sys-todo-summary { grid-template-columns:repeat(2,minmax(0,1fr)); } .sys-todo-filter label, .sys-todo-filter label.sys-todo-filter__keyword { flex-basis:10rem; } .sys-todo-field--3,.sys-todo-field--4,.sys-todo-field--6 { grid-column:span 12; } .sys-todo-table-wrap { max-height:65vh; } } + @media (max-width:720px) { .sys-todo-summary { grid-template-columns:repeat(2,minmax(0,1fr)); } .sys-todo-filter label, .sys-todo-filter label.sys-todo-filter__keyword { flex-basis:10rem; } .sys-todo-field--3,.sys-todo-field--4,.sys-todo-field--6 { grid-column:span 12; } }
@@ -304,7 +307,7 @@ 类型内容序号待办事项总负责人责任人 - 开始时间完成时间状态完成情况完成截图备注操作 + 开始时间完成时间状态完成情况完成截图备注 @@ -386,26 +389,16 @@ @endif
{{ $item->notes ?: '—' }}
- -
- -
- @csrf - @method('DELETE') - -
-
- @empty -
当前筛选条件下没有待办事项。
+
当前筛选条件下没有待办事项。
@endforelse
- 点击表内任意事项可直接编辑;表格在框内滚动,表头和操作列保持可见。 + 共 {{ number_format($items->count()) }} 条,已全部显示。点击任意事项行可直接编辑。
- @if ($items->hasPages()) -
- 共 {{ number_format($items->total()) }} 条 · 第 {{ $items->currentPage() }} / {{ $items->lastPage() }} 页 - - @if ($items->onFirstPage()) - 上一页 - @else - 上一页 - @endif - @if ($items->hasMorePages()) - 下一页 - @else - 下一页 - @endif - -
- @endif -
@csrf @@ -486,12 +461,32 @@
+
+ +
+ @csrf + @method('DELETE') +
+ + 确认删除待办 +
+
+ 删除后这条待办及其完成截图将不再显示,操作无法撤销。 + 当前待办 +
+
+ + +
+
+
+

完成截图预览

@@ -529,8 +524,13 @@ var ownerOptionInputs = Array.prototype.slice.call( dialog.querySelectorAll('[data-sys-todo-owner-options] input[type="checkbox"]') ); + var deleteButton = dialog.querySelector('[data-sys-todo-open-delete]'); + var deleteConfirm = document.getElementById('sysTodoDeleteConfirm'); + var deleteForm = deleteConfirm.querySelector('[data-sys-todo-delete-form]'); + var deleteTitle = deleteConfirm.querySelector('[data-sys-todo-delete-title]'); var routes = @json($todoRoutes, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); var currentTodoId = null; + var currentTodoTitle = ''; var uploadPrompt = '点击选择、拖入此区域或直接粘贴,支持多张,每张不超过 10 MB。'; var ownerFilter = document.querySelector('[data-sys-todo-owner-filter]'); var ownerSummary = ownerFilter.querySelector('[data-sys-todo-owner-summary]'); @@ -661,10 +661,12 @@ function openDialog(payload) { currentTodoId = payload && payload.id ? payload.id : null; + currentTodoTitle = payload && payload.title ? payload.title : ''; form.reset(); methodInput.value = currentTodoId ? 'PATCH' : 'POST'; form.action = currentTodoId ? routes.update.replace('__TODO__', currentTodoId) : routes.store; title.textContent = currentTodoId ? '编辑待办' : '新增待办'; + deleteButton.hidden = !currentTodoId; if (payload) { setCategoryValue(payload.category); setValue('section', payload.section); @@ -724,6 +726,19 @@ else dialog.removeAttribute('open'); } + function openDeleteConfirm() { + if (!currentTodoId) return; + deleteForm.action = routes.destroy.replace('__TODO__', currentTodoId); + deleteTitle.textContent = currentTodoTitle || '当前待办'; + if (typeof deleteConfirm.showModal === 'function') deleteConfirm.showModal(); + else deleteConfirm.setAttribute('open', ''); + } + + function closeDeleteConfirm() { + if (typeof deleteConfirm.close === 'function') deleteConfirm.close(); + else deleteConfirm.removeAttribute('open'); + } + document.addEventListener('click', function (event) { var image = event.target.closest('[data-sys-todo-image-url]'); if (image) { @@ -742,9 +757,8 @@ }); return; } - var edit = event.target.closest('[data-sys-todo-edit]'); - if (edit) { - openDialog(decodePayload(edit.getAttribute('data-sys-todo-edit'))); + if (event.target.closest('[data-sys-todo-open-delete]')) { + openDeleteConfirm(); return; } var row = event.target.closest('[data-sys-todo-row-edit]'); @@ -753,6 +767,7 @@ return; } if (event.target.closest('[data-sys-todo-close]')) closeDialog(); + if (event.target.closest('[data-sys-todo-delete-close]')) closeDeleteConfirm(); if (event.target.closest('[data-sys-todo-image-close]')) closeImageViewer(); if (event.target.closest('[data-sys-todo-choose-files]')) screenshotInput.click(); }); @@ -772,6 +787,9 @@ imageViewer.addEventListener('click', function (event) { if (event.target === imageViewer) closeImageViewer(); }); + deleteConfirm.addEventListener('click', function (event) { + if (event.target === deleteConfirm) closeDeleteConfirm(); + }); categorySelect.addEventListener('change', syncCategoryValue); newCategoryInput.addEventListener('input', function () { if (categorySelect.value === '__new__') syncCategoryValue(); diff --git a/tests/Feature/Business/SystemizationTodosTest.php b/tests/Feature/Business/SystemizationTodosTest.php index fc6730d0..af107cc8 100644 --- a/tests/Feature/Business/SystemizationTodosTest.php +++ b/tests/Feature/Business/SystemizationTodosTest.php @@ -41,6 +41,10 @@ class SystemizationTodosTest extends FeatureTestCase ->assertSee('data-sys-todo-new-category-input', false) ->assertSeeText('+ 新增类型') ->assertSee('data-sys-todo-choose-files', false) + ->assertSee('data-sys-todo-open-delete', false) + ->assertSee('id="sysTodoDeleteConfirm"', false) + ->assertDontSee('操作', false) + ->assertDontSeeText('下一页') ->assertSee('id="sysTodoImageViewer"', false); $this->post(route('business.systemization-todos.store'), [ @@ -195,7 +199,7 @@ class SystemizationTodosTest extends FeatureTestCase ['__overdue__', '待办'], array_column($pageContent['todoStatusOptions']->all(), 'value'), ); - $pageItems = $pageContent['items']->getCollection(); + $pageItems = $pageContent['items']; $this->assertSame( [1, 2], $pageItems->where('category', '收入') @@ -258,6 +262,34 @@ class SystemizationTodosTest extends FeatureTestCase ); } + public function test_page_renders_all_todos_on_one_continuous_list(): void + { + $this->loginAs(); + + foreach (range(1, 55) as $index) { + $this->createTodo( + $index % 2 === 0 ? '收入' : '成本', + '连续列表测试', + '连续事项 ' . $index, + '2026-11-30', + $index, + ); + } + + $response = $this->get(route('business.pages.show', [ + 'section' => 'other', + 'page' => 'systemization-todos', + ]))->assertOk(); + + $content = $response->viewData('content'); + $this->assertCount(55, $content['items']); + $this->assertTrue($content['items']->pluck('title')->contains('连续事项 55')); + $response->assertSee('连续事项 55') + ->assertSeeText('共 55 条,已全部显示') + ->assertDontSeeText('下一页') + ->assertDontSeeText('上一页'); + } + private function createTodo( string $category, string $section,