From c9777cbff8d94bb9d0d0dbdf50ea2dc0405066a8 Mon Sep 17 00:00:00 2001 From: qing <1776177662@qq.com> Date: Tue, 11 Aug 2026 10:06:33 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=89=8D=E7=AB=AF=E5=8D=A1=E7=89=87?= =?UTF-8?q?=E8=A7=82=E7=9C=8B=E6=95=B0/=E5=AD=90=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E6=95=B0=E6=8E=A5=E7=BA=BF=E5=90=8E=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dnfs2 get_notes 为每个节点附上 child_count(一次 IN 批量查询统计子节点数,best-effort) - dnfs.js 卡片眼睛=views 观看数、转发=child_count 子节点数(原 share_count/visit_count 后端无字段恒为 0) --- dnfs2/src/dnfs2.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++ fsys/public/js/dnfs.js | 7 ++++--- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/dnfs2/src/dnfs2.cpp b/dnfs2/src/dnfs2.cpp index c3952c9..c16daac 100644 --- a/dnfs2/src/dnfs2.cpp +++ b/dnfs2/src/dnfs2.cpp @@ -693,6 +693,45 @@ private: } } + // 统计各节点的子节点数(get_notes 用于前端"分享数"展示)。 + // 用一次 IN 批量查询所有孙节点(仅取 pid 列,避免拉取 content),按 pid 分组计数, + // 避免对每个节点单独查询。best-effort:任何失败仅记 WARNING 并返回已有结果, + // 绝不影响 get_notes 主流程(前端缺省显示 0)。 + std::unordered_map _child_counts(const json::array& items) { + std::unordered_map counts; + try { + json::array ids; + for (const auto& item : items) { + if (item.is_object() && item.as_object().contains("id") + && item.as_object().at("id").is_int64()) { + ids.push_back(item.as_object().at("id").as_int64()); + } + } + if (ids.empty()) return counts; + + json::object payload; + payload["action"] = "select"; + payload["table"] = "Notes"; + payload["columns"] = json::array{"pid"}; + payload["where"] = json::object{{"pid", json::object{{"in", ids}}}}; + + DbResult r = _call_db(payload); + if (!r.success || !r.data.is_array()) { + _log("WARNING", "dnfs2", "child_count 统计失败: " + r.error); + return counts; + } + for (const auto& row : r.data.as_array()) { + if (row.is_object() && row.as_object().contains("pid") + && row.as_object().at("pid").is_int64()) { + counts[row.as_object().at("pid").as_int64()]++; + } + } + } catch (const std::exception& e) { + _log("WARNING", "dnfs2", std::string("child_count 统计异常: ") + e.what()); + } + return counts; + } + // ---- Token 验签(通过 gateway /whoami)--------------------------------- struct UserInfo { @@ -904,6 +943,8 @@ private: if (r.data.is_array()) { json::array result = r.data.as_array(); + // 一次性统计各节点的子节点数(供前端"分享数"展示),避免逐节点查询 + auto child_counts = _child_counts(result); for (auto& item : result) { if (item.is_object()) { json::object& note = item.as_object(); @@ -916,6 +957,10 @@ private: } } note["can_operate"] = can_operate; + int64_t nid = (note.contains("id") && note.at("id").is_int64()) + ? note.at("id").as_int64() : 0; + auto cit = child_counts.find(nid); + note["child_count"] = (cit != child_counts.end()) ? cit->second : 0; } } _log("INFO", "dnfs2", "get_notes 查询 pid=" + std::to_string(pid) diff --git a/fsys/public/js/dnfs.js b/fsys/public/js/dnfs.js index 868ff21..49e4bf6 100644 --- a/fsys/public/js/dnfs.js +++ b/fsys/public/js/dnfs.js @@ -1011,12 +1011,13 @@ function renderCards(list) { owner_name.textContent = owner_text; wrt_div.appendChild(owner_avatar); wrt_div.appendChild(owner_name); - // 互动统计:眼睛=观看、爱心=点赞、转发=分享(后端 Notes 表暂无计数字段,缺省显示 0) + // 互动统计:眼睛=观看数(后端 views 列)、爱心=点赞、转发=子节点数(后端 child_count)。 + // views / child_count 由 dnfs2 get_notes 返回;like_count 后端暂无字段,缺省显示 0。 let sts_div = document.createElement('div'); sts_div.className = "card-stats"; - sts_div.appendChild(makeStatItem(ICON_EYE, item.visit_count)); + sts_div.appendChild(makeStatItem(ICON_EYE, item.views)); sts_div.appendChild(makeStatItem(ICON_HEART, item.like_count)); - sts_div.appendChild(makeStatItem(ICON_SHARE, item.share_count)); + sts_div.appendChild(makeStatItem(ICON_SHARE, item.child_count)); // 卡片操作按钮:编辑 / 移动 / 删除(stopPropagation 防止触发卡片自身的点入跳转) // 按钮组整体按 can_operate 显隐:操作权由后端 get_notes 按 owner / is_admin 判定, // 与 delete_note / update_note 鉴权口径一致(移动本质也是 update_note);