From 94b5581267c3ec83717ce1c5541d4b173cee43c1 Mon Sep 17 00:00:00 2001 From: yueyang <2495544247@qq.com> Date: Tue, 27 Oct 2026 13:10:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E5=BE=85=E5=8A=9E?= =?UTF-8?q?=E6=88=AA=E5=9B=BE=E5=88=A0=E9=99=A4=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/systemization-todos.blade.php | 87 ++++++++++++++++--- .../Business/SystemizationTodosTest.php | 4 + 2 files changed, 78 insertions(+), 13 deletions(-) diff --git a/resources/views/business/pages/systemization-todos.blade.php b/resources/views/business/pages/systemization-todos.blade.php index d93a6f1e..3bc65340 100644 --- a/resources/views/business/pages/systemization-todos.blade.php +++ b/resources/views/business/pages/systemization-todos.blade.php @@ -147,10 +147,22 @@ .sys-todo-upload-note { flex:1 1 15rem; color:#666; font-size:.72rem; line-height:1.5; } .sys-todo-field.is-dragging { outline:2px dashed var(--sys-gold); outline-offset:3px; border-radius:.55rem; background:var(--sys-gold-soft); } .sys-todo-existing { display:flex; flex-wrap:wrap; gap:.55rem; margin-top:.45rem; } - .sys-todo-existing__item { display:grid; gap:.25rem; width:8.5rem; padding:.4rem; border:1px solid #e4dccd; border-radius:.45rem; background:#fcfaf5; font-size:.7rem; } - .sys-todo-existing__item button { display:block; width:100%; padding:0; border:0; border-radius:.3rem; background:#fff; cursor:zoom-in; overflow:hidden; } - .sys-todo-existing__item img { display:block; width:100%; height:5rem; object-fit:contain; background:#fff; } - .sys-todo-existing__item label { display:flex; align-items:center; gap:.25rem; color:#b80000; } + .sys-todo-existing__item { position:relative; display:flex; flex-direction:column; gap:.35rem; width:9.25rem; padding:.45rem; border:1px solid #e4dccd; border-radius:.45rem; background:#fcfaf5; font-size:.7rem; transition:border-color 150ms ease,background 150ms ease; } + .sys-todo-existing__preview { display:block; width:100%; padding:0; border:1px solid #e4dccd; border-radius:.35rem; background:#fff; cursor:zoom-in; overflow:hidden; } + .sys-todo-existing__preview:hover { border-color:var(--sys-gold); } + .sys-todo-existing__preview:focus-visible { outline:2px solid var(--sys-gold); outline-offset:2px; } + .sys-todo-existing__preview img { display:block; width:100%; height:4.75rem; object-fit:contain; background:#fff; transition:opacity 150ms ease,filter 150ms ease; } + .sys-todo-existing__name { display:block; overflow:hidden; color:#595959; line-height:1.35; text-overflow:ellipsis; white-space:nowrap; } + .sys-todo-existing__state { position:absolute; top:.62rem; right:.62rem; z-index:2; display:none; padding:.08rem .36rem; border:1px solid #dba9a9; border-radius:999px; background:rgba(255,247,247,.96); color:#b80000; font-size:.62rem; font-weight:600; } + .sys-todo-existing__remove { display:inline-flex; align-items:center; justify-content:center; gap:.22rem; width:100%; min-height:1.8rem; margin-top:auto; padding:0 .4rem; border:1px solid #e7c3c3; border-radius:.35rem; background:#fff; color:#b80000; font:inherit; font-size:.7rem; font-weight:500; white-space:nowrap; cursor:pointer; transition:border-color 150ms ease,background 150ms ease,color 150ms ease; } + .sys-todo-existing__remove:hover { border-color:#d89a9a; background:#fff3f3; } + .sys-todo-existing__remove:focus-visible { outline:2px solid #b80000; outline-offset:2px; } + .sys-todo-existing__remove .material-icons-outlined { font-size:.9rem; } + .sys-todo-existing__remove[aria-pressed="true"] { border-color:#b80000; background:#b80000; color:#fff; } + .sys-todo-existing__item.is-marked-for-removal { border-color:#d9aaaa; background:#fff6f6; } + .sys-todo-existing__item.is-marked-for-removal .sys-todo-existing__preview img { opacity:.45; filter:grayscale(1); } + .sys-todo-existing__item.is-marked-for-removal .sys-todo-existing__name { color:#8a3030; } + .sys-todo-existing__item.is-marked-for-removal .sys-todo-existing__state { display:inline-flex; } .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; } @@ -1271,6 +1283,21 @@ else groupDialog.removeAttribute('open'); } + function toggleAttachmentRemoval(button) { + var marked = button.getAttribute('aria-pressed') !== 'true'; + var item = button.closest('.sys-todo-existing__item'); + var input = item ? item.querySelector('[data-sys-todo-remove-input]') : null; + var label = button.querySelector('[data-sys-todo-remove-label]'); + var name = button.getAttribute('data-sys-todo-remove-name') || ''; + + button.setAttribute('aria-pressed', marked ? 'true' : 'false'); + button.setAttribute('aria-label', (marked ? '取消删除截图:' : '删除截图:') + name); + button.title = marked ? '再次点击可取消,保存待办后删除' : '标记删除,保存待办后生效'; + if (label) label.textContent = marked ? '取消删除' : '删除'; + if (input) input.disabled = !marked; + if (item) item.classList.toggle('is-marked-for-removal', marked); + } + function openDialog(payload) { currentTodoId = payload && payload.id ? payload.id : null; currentTodoTitle = payload && payload.title ? payload.title : ''; @@ -1320,10 +1347,15 @@ existing.replaceChildren(); ((payload && payload.attachments) || []).forEach(function (attachment) { - var item = document.createElement('span'); + var item = document.createElement('div'); item.className = 'sys-todo-existing__item'; + var state = document.createElement('span'); + state.className = 'sys-todo-existing__state'; + state.textContent = '保存后删除'; + item.appendChild(state); var preview = document.createElement('button'); preview.type = 'button'; + preview.className = 'sys-todo-existing__preview'; preview.setAttribute('data-sys-todo-image-url', attachment.url); preview.setAttribute('data-sys-todo-image-name', attachment.name); preview.title = '点击预览:' + attachment.name; @@ -1332,14 +1364,36 @@ image.alt = attachment.name; preview.appendChild(image); item.appendChild(preview); - var label = document.createElement('label'); - var checkbox = document.createElement('input'); - checkbox.type = 'checkbox'; - checkbox.name = 'remove_attachments[]'; - checkbox.value = attachment.id; - label.appendChild(checkbox); - label.appendChild(document.createTextNode('删除截图')); - item.appendChild(label); + var fileName = document.createElement('span'); + fileName.className = 'sys-todo-existing__name'; + fileName.textContent = attachment.name || '完成截图'; + fileName.title = attachment.name || '完成截图'; + item.appendChild(fileName); + var remove = document.createElement('button'); + remove.type = 'button'; + remove.className = 'sys-todo-existing__remove'; + remove.setAttribute('data-sys-todo-remove-attachment', ''); + remove.setAttribute('data-sys-todo-remove-name', attachment.name || '完成截图'); + remove.setAttribute('aria-pressed', 'false'); + remove.setAttribute('aria-label', '删除截图:' + (attachment.name || '完成截图')); + remove.title = '标记删除,保存待办后生效'; + var removeIcon = document.createElement('span'); + removeIcon.className = 'material-icons-outlined'; + removeIcon.setAttribute('aria-hidden', 'true'); + removeIcon.textContent = 'delete_outline'; + var removeLabel = document.createElement('span'); + removeLabel.setAttribute('data-sys-todo-remove-label', ''); + removeLabel.textContent = '删除'; + remove.appendChild(removeIcon); + remove.appendChild(removeLabel); + item.appendChild(remove); + var removeInput = document.createElement('input'); + removeInput.type = 'hidden'; + removeInput.name = 'remove_attachments[]'; + removeInput.value = attachment.id; + removeInput.disabled = true; + removeInput.setAttribute('data-sys-todo-remove-input', ''); + item.appendChild(removeInput); existing.appendChild(item); }); @@ -1389,6 +1443,13 @@ ); return; } + var removeAttachment = event.target.closest('[data-sys-todo-remove-attachment]'); + if (removeAttachment) { + event.preventDefault(); + event.stopPropagation(); + toggleAttachmentRemoval(removeAttachment); + return; + } var inlineAdd = event.target.closest('[data-sys-todo-inline-add]'); if (inlineAdd) { event.preventDefault(); diff --git a/tests/Feature/Business/SystemizationTodosTest.php b/tests/Feature/Business/SystemizationTodosTest.php index 455ae79b..58fdbc68 100644 --- a/tests/Feature/Business/SystemizationTodosTest.php +++ b/tests/Feature/Business/SystemizationTodosTest.php @@ -64,6 +64,10 @@ class SystemizationTodosTest extends FeatureTestCase ->assertSeeText('+ 新增内容') ->assertSeeText('在类型、内容下方的+直接新增') ->assertSee('data-sys-todo-choose-files', false) + ->assertSee('data-sys-todo-remove-attachment', false) + ->assertSee('data-sys-todo-remove-input', false) + ->assertSee('is-marked-for-removal', false) + ->assertSee('保存后删除', false) ->assertSee('data-sys-todo-open-delete', false) ->assertSee('id="sysTodoDeleteConfirm"', false) ->assertSee('data-sys-todo-table-wrap', false) -- 2.47.2