评论附件支持拖拽 + 首页卡片同步标题 (#79)

用户 2026-11-05:
  「评论框下面的附件也需要可以拖动添加。」
  「首页卡片没有刷新。」

① 评论附件拖拽
   给 `.cmt-attach-row` 挂 `data-cmt-drop`,由 task_panel.js 接管
   dragover / dragenter / dragleave / drop。

   🔴 核心技术点:`<input type=file>.files` 是**只读**的,
      不能直接 `input.files = event.dataTransfer.files`(某些内核静默失败)。
      必须用 DataTransfer 重建 FileList 再赋回去:
          var dt = new DataTransfer();
          dt.items.add(file);
          input.files = dt.files;      ← 这个赋值是允许的
      而且**必须真的赋给 input** —— 否则只是"看起来加上了",
      表单提交时浏览器一个文件都不带。

   ⚠️ 累加语义:用户可能先拖一张再拖一张,所以每次把 input.files
      现有内容 + 新拖入的合并后写回。
   ⚠️ 去重:按 name+size+lastModified 判重,否则"只拖一次却传上去两张一样的"。
   ⚠️ dragover 必须 preventDefault(不拦的话浏览器把文件当"打开",
      直接跳走、当前页面全丢)。
   ⚠️ 与「任务附件」那条 `[data-tk-drop-box]` 是**两条独立的路**:
      那个是"点了/拖了立刻上传"(任务已存在),
      这个是"挂到评论表单、点发表才一起提交"。

   实测(Playwright + 真实 DataTransfer):
     拖入 a.txt+b.png => count=2 ✅
     再拖 c.jpg      => count=3 ✅ 累加
     重复拖 a.txt    => count=3 ✅ 去重
     FormData(form)  => ["a.txt","b.png","c.jpg"] ✅ 提交时真会传

② 首页卡片同步标题
   根因:`syncRow()` 原来**只管状态徽标和复选框**,代码第一行就是
   `if (!d || !d.status) return;`,压根不碰标题。
   而 #78 之后面板里能改标题了 ⇒ 改完点保存,卡片上还是旧标题。

   改两处:
   · `task_panel_json()` 返回值补 `title`(服务端直接给,不依赖 DOM 还在)
   · `syncRow()` 补标题同步:`.dash-what` 的文本 + `title` 属性
     (`title` 是悬停提示,不同步会出现"悬停是旧标题"的怪事),
     并把 `data-fb-entry` 里的 JSON title 一并改掉
     (否则"卡片上是新标题、再点开浮层显示旧标题")。
     读不到 d.title 时兜底从 `#tkp-title` 输入框读。
This commit is contained in:
2026-11-05 18:32:40 +08:00
parent 11aa7c6ca5
commit cb846d378f
4 changed files with 172 additions and 3 deletions
+5
View File
@@ -599,6 +599,11 @@ function task_panel_json(int $taskId, string $msg = '', bool $ok = true): void
'id' => $taskId,
'status' => (string)($t['status'] ?? ''),
'word' => \App\Task::statusWord((string)($t['status'] ?? 'todo')),
/* 🔴 #79(用户 2026-11-05):「首页卡片没有刷新。」
前端 `syncRow()` 原来只同步状态徽标,不同步标题。
标题可以从面板输入框读,但那条路依赖 DOM 还在 ——
服务端直接回一份才是稳的(同一个函数给所有面板动作复用)。 */
'title' => (string)($t['title'] ?? ''),
'html' => $html,
], JSON_UNESCAPED_UNICODE);
exit;