feat: 管理台内容状态过滤+预览、批量上架/灰掉、标签拖拽调整层级
Build and Deploy / build (push) Successful in 1m37s
Build and Deploy / deploy (push) Successful in 31s

This commit is contained in:
cheney
2026-09-21 11:15:26 +08:00
parent 7e62db31b8
commit 3f7b48325f
7 changed files with 366 additions and 30 deletions
+49 -13
View File
@@ -16,14 +16,44 @@
<main class="admin-main">
<!-- 内容管理 -->
<section id="sec-content" class="active">
<p class="anno">// table: entries · 状态 active | greyed | pending</p>
<p class="anno">// table: entries · 状态 active | greyed | pending · 预览 = 按当前状态模拟前台展示</p>
<h1>内容管理</h1>
<p class="admin-desc">全部收录条目。灰掉 = 暂不可见但保留数据;删除为物理删除,需确认。</p>
<table class="data-table" style="margin-top:22px">
<thead><tr><th>标题</th><th>类型</th><th>状态</th><th>更新时间</th><th style="text-align:right">操作</th></tr></thead>
<tbody>
<% for (const e of entries) { %>
<div class="status-chips">
<a class="chip <%= status === 'all' ? 'is-active' : '' %>" href="/admin?status=all">全部 <span class="mono"><%= statusCounts.all %></span></a>
<a class="chip <%= status === 'active' ? 'is-active' : '' %>" href="/admin?status=active">上线 <span class="mono"><%= statusCounts.active %></span></a>
<a class="chip <%= status === 'pending' ? 'is-active' : '' %>" href="/admin?status=pending">待核验 <span class="mono"><%= statusCounts.pending %></span></a>
<a class="chip <%= status === 'greyed' ? 'is-active' : '' %>" href="/admin?status=greyed">灰掉 <span class="mono"><%= statusCounts.greyed %></span></a>
<span class="spacer"></span>
<span class="mono page-hint">第 <%= page %> / <%= totalPages %> 页</span>
</div>
<div class="batch-bar">
<button class="btn btn-sm" type="button" data-action="entry-select-all">全选本页</button>
<button class="btn btn-sm" type="button" data-action="entry-batch" data-status="active">批量上架</button>
<button class="btn btn-sm" type="button" data-action="entry-batch" data-status="greyed">批量灰掉</button>
<span class="mono batch-count" id="batch-count">已选 0 项</span>
</div>
<table class="data-table" style="margin-top:14px">
<thead>
<tr>
<th style="width:36px"><input type="checkbox" class="entry-check-all" title="全选本页" /></th>
<th>标题</th>
<th>类型</th>
<th>状态</th>
<th>更新时间</th>
<th style="text-align:right">操作</th>
</tr>
</thead>
<tbody>
<% if (entries.length === 0) { %>
<tr><td colspan="6" class="mono" style="text-align:center;color:var(--ink-dim);padding:28px">当前筛选下没有条目</td></tr>
<% } %>
<% for (const e of entries) { %>
<tr data-id="<%= e.id %>">
<td style="text-align:center"><input type="checkbox" class="entry-check" data-id="<%= e.id %>" /></td>
<td>
<b><%= e.title %></b><br />
<span class="mono" style="font-size:11px;color:var(--ink-dim)"><%= (e.tags || []).join(' · ') || '—' %></span>
@@ -38,6 +68,7 @@
<td>
<div class="row-actions">
<a class="btn btn-sm" href="/admin/entries/<%= e.id %>/edit">编辑</a>
<a class="btn btn-sm" href="/entries/<%= e.slug %>?preview=1" target="_blank" rel="noopener">预览</a>
<% if (e.status !== 'active') { %>
<button class="btn btn-sm" type="button" data-action="entry-status" data-id="<%= e.id %>" data-status="active">上架</button>
<% } else { %>
@@ -52,11 +83,15 @@
<% } %>
</tbody>
</table>
<div class="pager">
<a class="btn btn-sm <%= page <= 1 ? 'btn-disabled' : '' %>" href="/admin?status=<%= status %>&page=<%= Math.max(1, page - 1) %>">上一页</a>
<a class="btn btn-sm <%= page >= totalPages ? 'btn-disabled' : '' %>" href="/admin?status=<%= status %>&page=<%= page + 1 %>">下一页</a>
</div>
</section>
<!-- 标签管理 -->
<section id="sec-tags">
<p class="anno">// tree: tags · 删除父级时子级自动上移;移动到自己的子级会被拒绝</p>
<p class="anno">// tree: tags · 拖到某个标签上 = 移为其子级;拖到下方空白处 = 移回顶层标签组</p>
<h1>标签管理</h1>
<div style="display:flex;gap:10px;margin-top:18px">
<button class="btn btn-primary btn-sm" type="button" data-action="tag-add">新增顶层标签组</button>
@@ -64,17 +99,18 @@
</div>
<div class="tagmgr">
<div class="panel-box">
<h3>标签树 <span class="mono" style="font-weight:400;font-size:12px;color:var(--ink-dim)">(#ID 用于「移动」时填写目标)</span></h3>
<ul class="tag-tree">
<% for (const root of tagTreeAdmin) { %><%- include('partials/tag-node', { node: root }) %><% } %>
</ul>
<h3>标签树 <span class="mono" style="font-weight:400;font-size:12px;color:var(--ink-dim)">(可直接拖动节点调整层级,变更即时生效)</span></h3>
<div class="tagmgr-tree" id="admin-tag-tree" style="min-height:120px">
<p class="mono dim">加载中…</p>
</div>
<p class="dnd-hint mono dim">按住节点拖动:落到某个标签上 = 变为它的子级 · 落到下方空白处 = 移回顶层</p>
</div>
<div class="panel-box">
<h3>规则说明</h3>
<p style="font-size:13.5px;color:var(--ink-dim)">
标签可无限嵌套,列表页按组过滤时会自动包含所有后代标签的条目。
「移动」填写目标标签 ID;移动到自身子级会被拒绝以防止成环。
删除父标签时其子标签自动上移一级。
标签可无限嵌套,列表页按组过滤时会自动包含所有后代标签的条目。<br /><br />
拖动标签到另一标签上可快速调整层级;拖到空白处可移回顶层。<br />
删除父标签时其子标签自动上移一级,关联关系解除。
</p>
</div>
</div>