feat(ai-cases-write): 등록된 사례 목록 5건 단위 페이징
- 최신순 정렬 후 페이지당 5개, 이전/다음 네비 - edit·page 쿼리 유지, 목록 영역 스타일 보강 Made-with: Cursor
This commit is contained in:
@@ -677,6 +677,16 @@ button.ai-case-inline-link:hover {
|
|||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.admin-story-list-pagination {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 14px;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid #f3f4f6;
|
||||||
|
}
|
||||||
|
|
||||||
.btn-sm {
|
.btn-sm {
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|||||||
24
server.js
24
server.js
@@ -1167,6 +1167,8 @@ pageRouter.get("/ai-explore/task-checklist", (req, res) =>
|
|||||||
opsState: normalizeOpsState(),
|
opsState: normalizeOpsState(),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
const AI_SUCCESS_ADMIN_LIST_PAGE_SIZE = 5;
|
||||||
|
|
||||||
pageRouter.get("/ai-cases/write", (req, res) => {
|
pageRouter.get("/ai-cases/write", (req, res) => {
|
||||||
if (!res.locals.adminMode) {
|
if (!res.locals.adminMode) {
|
||||||
return res.status(403).send(
|
return res.status(403).send(
|
||||||
@@ -1180,11 +1182,31 @@ pageRouter.get("/ai-cases/write", (req, res) => {
|
|||||||
const m = meta.find((x) => x.slug === editSlug);
|
const m = meta.find((x) => x.slug === editSlug);
|
||||||
if (m) story = enrichAiSuccessStory(m);
|
if (m) story = enrichAiSuccessStory(m);
|
||||||
}
|
}
|
||||||
|
const sortedStories = [...meta].sort((a, b) => {
|
||||||
|
const da = new Date(a.publishedAt || a.updatedAt || a.createdAt || 0);
|
||||||
|
const db = new Date(b.publishedAt || b.updatedAt || b.createdAt || 0);
|
||||||
|
return db - da;
|
||||||
|
});
|
||||||
|
const pageRaw = req.query.page;
|
||||||
|
const pageNum = Math.max(1, parseInt(Array.isArray(pageRaw) ? pageRaw[0] : pageRaw, 10) || 1);
|
||||||
|
const totalCount = sortedStories.length;
|
||||||
|
const totalPages = Math.max(1, Math.ceil(totalCount / AI_SUCCESS_ADMIN_LIST_PAGE_SIZE));
|
||||||
|
const currentPage = Math.min(pageNum, totalPages);
|
||||||
|
const start = (currentPage - 1) * AI_SUCCESS_ADMIN_LIST_PAGE_SIZE;
|
||||||
|
const allStories = sortedStories.slice(start, start + AI_SUCCESS_ADMIN_LIST_PAGE_SIZE);
|
||||||
|
const listPagination = {
|
||||||
|
page: currentPage,
|
||||||
|
totalPages,
|
||||||
|
totalCount,
|
||||||
|
hasPrev: currentPage > 1,
|
||||||
|
hasNext: currentPage < totalPages,
|
||||||
|
};
|
||||||
res.render("ai-cases-write", {
|
res.render("ai-cases-write", {
|
||||||
activeMenu: "ai-cases",
|
activeMenu: "ai-cases",
|
||||||
adminMode: true,
|
adminMode: true,
|
||||||
story,
|
story,
|
||||||
allStories: meta,
|
allStories,
|
||||||
|
listPagination,
|
||||||
editSlug: editSlug || null,
|
editSlug: editSlug || null,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -46,18 +46,42 @@
|
|||||||
<p class="muted admin-hint">슬러그는 URL에 쓰이므로 영문·숫자·하이픈만 사용하세요. <strong>원문 PDF 경로</strong>(<code>/public/...</code>)가 있으면 상세는 PDF 페이지 이미지로 보여 주며, 이때 <strong>본문(Markdown)은 비워도 됩니다</strong>. PDF가 없을 때는 본문이 필수입니다.</p>
|
<p class="muted admin-hint">슬러그는 URL에 쓰이므로 영문·숫자·하이픈만 사용하세요. <strong>원문 PDF 경로</strong>(<code>/public/...</code>)가 있으면 상세는 PDF 페이지 이미지로 보여 주며, 이때 <strong>본문(Markdown)은 비워도 됩니다</strong>. PDF가 없을 때는 본문이 필수입니다.</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<% if (allStories.length) { %>
|
<% if (typeof listPagination !== 'undefined' && listPagination.totalCount > 0) { %>
|
||||||
<section class="panel">
|
<section class="panel">
|
||||||
<h2>등록된 사례</h2>
|
<div class="section-head" style="margin-bottom:8px;align-items:baseline;">
|
||||||
|
<h2 style="margin:0;">등록된 사례</h2>
|
||||||
|
<% if (listPagination.totalPages > 1) { %>
|
||||||
|
<span class="muted" style="font-size:13px;">총 <%= listPagination.totalCount %>건 · <%= listPagination.page %>/<%= listPagination.totalPages %> 페이지</span>
|
||||||
|
<% } else { %>
|
||||||
|
<span class="muted" style="font-size:13px;">총 <%= listPagination.totalCount %>건</span>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
<ul class="admin-story-list">
|
<ul class="admin-story-list">
|
||||||
<% allStories.forEach(function(s) { %>
|
<% allStories.forEach(function(s) { %>
|
||||||
<li>
|
<li>
|
||||||
<a href="/ai-cases/write?edit=<%= s.slug %>"><strong><%= s.title %></strong></a>
|
<% var _listPageQ = listPagination.page > 1 ? ('&page=' + listPagination.page) : ''; %>
|
||||||
|
<a href="/ai-cases/write?edit=<%= encodeURIComponent(s.slug) %><%= _listPageQ %>"><strong><%= s.title %></strong></a>
|
||||||
<span class="muted">/<%= s.slug %></span>
|
<span class="muted">/<%= s.slug %></span>
|
||||||
<button type="button" class="btn-ghost btn-sm js-delete-story" data-id="<%= s.id %>" data-title="<%= s.title %>">삭제</button>
|
<button type="button" class="btn-ghost btn-sm js-delete-story" data-id="<%= s.id %>" data-title="<%= s.title %>">삭제</button>
|
||||||
</li>
|
</li>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
</ul>
|
</ul>
|
||||||
|
<% if (listPagination.totalPages > 1) { %>
|
||||||
|
<nav class="admin-story-list-pagination" aria-label="등록된 사례 페이지">
|
||||||
|
<% var _pq = editSlug ? ('edit=' + encodeURIComponent(editSlug) + '&') : ''; %>
|
||||||
|
<% if (listPagination.hasPrev) { %>
|
||||||
|
<a class="btn-ghost btn-sm" href="/ai-cases/write?<%= _pq %>page=<%= listPagination.page - 1 %>">이전</a>
|
||||||
|
<% } else { %>
|
||||||
|
<span class="btn-ghost btn-sm" style="opacity:0.45;pointer-events:none;">이전</span>
|
||||||
|
<% } %>
|
||||||
|
<span class="muted" style="font-size:13px;padding:0 8px;"><%= listPagination.page %> / <%= listPagination.totalPages %></span>
|
||||||
|
<% if (listPagination.hasNext) { %>
|
||||||
|
<a class="btn-ghost btn-sm" href="/ai-cases/write?<%= _pq %>page=<%= listPagination.page + 1 %>">다음</a>
|
||||||
|
<% } else { %>
|
||||||
|
<span class="btn-ghost btn-sm" style="opacity:0.45;pointer-events:none;">다음</span>
|
||||||
|
<% } %>
|
||||||
|
</nav>
|
||||||
|
<% } %>
|
||||||
</section>
|
</section>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user