From 33b6bd2201901164542210158cf17092b286e594 Mon Sep 17 00:00:00 2001 From: king Date: Wed, 16 Sep 2026 01:12:08 +0900 Subject: [PATCH] =?UTF-8?q?fix(project):=20=EC=84=A4=EB=AA=85=EB=9E=80=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=82=AD=EC=A0=9C=20=EC=8B=9C=20?= =?UTF-8?q?=EC=B2=A8=EB=B6=80=ED=8C=8C=EC=9D=BC=20=EB=AA=A9=EB=A1=9D?= =?UTF-8?q?=EC=97=90=EC=84=9C=EB=8F=84=20=EA=B0=99=EC=9D=B4=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 설명에 붙여넣기/업로드로 넣은 이미지는 실제로는 task_attachments 레코드라, 에디터에서 이미지만 지우면(× 버튼 또는 Delete/Backspace) 서버 첨부는 그대로 남아 첨부파일 목록에 계속 보였다. src 의 attachment id 를 뽑아 DELETE 호출까지 같이 하고, 첨부파일 목록도 새로고침한다. Co-Authored-By: Claude Sonnet 5 --- .../project/templates/project/inbox.html | 2 +- .../project/templates/project/index.html | 2 +- .../project/templates/project/project.html | 2 +- app/static/project.js | 37 ++++++++++++++++--- 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/app/modules/project/templates/project/inbox.html b/app/modules/project/templates/project/inbox.html index 432bb47..da75de5 100644 --- a/app/modules/project/templates/project/inbox.html +++ b/app/modules/project/templates/project/inbox.html @@ -45,5 +45,5 @@ {% endif %} - + {% endblock %} diff --git a/app/modules/project/templates/project/index.html b/app/modules/project/templates/project/index.html index fbf9fe9..0205590 100644 --- a/app/modules/project/templates/project/index.html +++ b/app/modules/project/templates/project/index.html @@ -392,5 +392,5 @@ - + {% endblock %} diff --git a/app/modules/project/templates/project/project.html b/app/modules/project/templates/project/project.html index f89ff45..10e568d 100644 --- a/app/modules/project/templates/project/project.html +++ b/app/modules/project/templates/project/project.html @@ -405,5 +405,5 @@ - + {% endblock %} diff --git a/app/static/project.js b/app/static/project.js index 31ea712..4994800 100644 --- a/app/static/project.js +++ b/app/static/project.js @@ -211,6 +211,12 @@ const descEditor = initDescEditor(); const subtaskBlock = initSubtaskBlock(); const linksBlock = initLinksBlock(); + if (descEditor) { + descEditor.setOnImageRemoved(function () { + const tid = el("pj-t-id").value; + if (tid) loadHomeAttachments(tid); + }); + } // 닫을 때(배경 클릭·Esc·취소 버튼) 수정한 내용이 있으면 저장할지 물어본다. let homeTaskSnapshot = null; @@ -1631,6 +1637,12 @@ const descEditor = initDescEditor(); const subtaskBlock = initSubtaskBlock(); const linksBlock = initLinksBlock(); + if (descEditor) { + descEditor.setOnImageRemoved(function () { + const tid = el("pj-t-id").value; + if (tid) loadAttachments(tid); + }); + } // 닫을 때(배경 클릭·Esc·취소 버튼) 수정한 내용이 있으면 저장할지 물어본다. // 하위업무/첨부/댓글/연결은 각자 즉시 저장돼서 여기서 추적할 필요 없다 — @@ -2139,6 +2151,22 @@ const imgDelBtn = imgTools.querySelector(".pj-img-del"); const imgHandle = imgTools.querySelector(".pj-img-handle"); let selectedImg = null; + let onImageRemoved = null; + + // 설명란 이미지는 첨부파일 업로드로 들어간 실제 첨부 레코드다 — 에디터에서 + // 지우면 첨부파일 목록에도 안 남게 서버 첨부도 같이 삭제한다. + async function deleteSelectedImage() { + if (!selectedImg) return; + const img = selectedImg; + const m = (img.getAttribute("src") || "").match(/\/attachments\/(\d+)\/inline/); + img.remove(); + selectImg(null); + if (!m) return; + try { + await api("DELETE", "/project/api/attachments/" + m[1]); + } catch (_) { /* 이미 지워졌을 수 있음 — 에디터에서는 이미 빠졌으니 조용히 무시 */ } + if (onImageRemoved) onImageRemoved(); + } function positionImgTools() { if (!selectedImg || !selectedImg.isConnected) { selectedImg = null; imgTools.hidden = true; return; } @@ -2161,10 +2189,7 @@ document.addEventListener("click", function (e) { if (selectedImg && !wrap.contains(e.target)) selectImg(null); }); - imgDelBtn.addEventListener("click", function () { - if (selectedImg) selectedImg.remove(); - selectImg(null); - }); + imgDelBtn.addEventListener("click", function () { deleteSelectedImage(); }); let dragging = false, dragStartX = 0, dragStartW = 0; imgHandle.addEventListener("mousedown", function (e) { if (!selectedImg) return; @@ -2190,8 +2215,7 @@ const active = document.activeElement; if (active && ["INPUT", "TEXTAREA", "SELECT"].indexOf(active.tagName) >= 0) return; e.preventDefault(); - selectedImg.remove(); - selectImg(null); + deleteSelectedImage(); }); // 업로드 버튼 클릭 → 파일 선택창이 뜨는 동안 contenteditable의 선택 범위가 @@ -2322,6 +2346,7 @@ setHtml: function (html) { selectImg(null); lastRange = null; box.innerHTML = html || ""; }, getHtml: function () { return box.innerHTML; }, isUploading: function () { return pendingUploads > 0; }, + setOnImageRemoved: function (fn) { onImageRemoved = fn; }, }; }